ls-models系列

AngularJS 教程
AngularJS Bootstrap
AngularJS 的首选样式表是 Twitter Bootstrap, Twitter Bootstrap 是目前最受欢迎的前端框架。
你可以在你的 AngularJS 应用中加入 Twitter Bootstrap,你可以在你的 &head&元素中添加如下代码:
&link rel="stylesheet" href="///bootstrap/3.3.4/css/bootstrap.min.css"&
如果站点在国内,建议使用百度静态资源库的Bootstrap,代码如下:
&link rel="stylesheet" href="///libs/bootstrap/3.3.4/css/bootstrap.min.css"&
以下是一个完整的 HTML 实例, 使用了 AngularJS 指令和 Bootstrap 类。
&!DOCTYPE html&&html&
&link rel="stylesheet"
href="/libs/bootstrap/3.3.4/css/bootstrap.min.css"&
&script src="/libs/angular.js/1.4.6/angular.min.js"&&/script&
ng-app="myApp" ng-controller="userCtrl"&
&div class="container"&&h3&Users&/h3&&table
class="table table-striped"&& &thead&&tr&
&&& &th&Edit&/th&&&& &th&First
Name&/th&&&& &th&Last Name&/th&& &/tr&&/thead&
& &tbody&&tr
ng-repeat="user in users"&&&& &td&
&&&&& &button class="btn" ng-click="editUser(user.id)"&
&span class="glyphicon glyphicon-pencil"&&/span&&&Edit
&/button&&&& &/td&&&& &td&{{ user.fName }}&/td&
&&& &td&{{ user.lName }}&/td&
&/tr&&/tbody&&/table&&hr&&button class="btn btn-success"
ng-click="editUser('new')"&
& &span class="glyphicon glyphicon-user"&&/span& Create New User
&/button&&hr&
&h3 ng-show="edit"&Create New User:&/h3&&h3 ng-hide="edit"&Edit
User:&/h3&&form class="form-horizontal"&&div class="form-group"&
&label class="col-sm-2 control-label"&First Name:&/label&& &div
class="col-sm-10"&
&&& &input type="text" ng-model="fName" ng-disabled="!edit"
placeholder="First Name"&& &/div&
&/div& &div class="form-group"&
&label class="col-sm-2 control-label"&Last Name:&/label&& &div
class="col-sm-10"&
&&& &input type="text" ng-model="lName" ng-disabled="!edit"
placeholder="Last Name"&& &/div&&/div&
&div class="form-group"&
&label class="col-sm-2 control-label"&Password:&/label&& &div
class="col-sm-10"&&&& &input type="password" ng-model="passw1"
placeholder="Password"&& &/div&&/div&
&div class="form-group"&
&label class="col-sm-2 control-label"&Repeat:&/label&& &div
class="col-sm-10"&&&& &input type="password" ng-model="passw2"
placeholder="Repeat Password"&& &/div&&/div&
&/form&&hr&
&button class="btn btn-success" ng-disabled="error || incomplete"&
& &span class="glyphicon glyphicon-save"&&/span& Save
Changes&/button&&/div&
&script src = "myUsers.js"&&/script&&/body&
AngularJS 指令
&html ng-app
为 &html& 元素定义一个应用(未命名)
&body ng-controller
为 &body& 元素定义一个控制器
&tr ng-repeat
循环 users 对象数组,每个 user 对象放在 &tr& 元素中。
&button ng-click
当点击 &button& 元素时调用函数 editUser()
&h3 ng-show
如果 edit = true 显示 &h3& 元素
&h3 ng-hide
如果 edit = true 隐藏 &h3& 元素
&input ng-model
为应用程序绑定 &input& 元素
&button ng-disabled
如果发生错误或者 incomplete = true 禁用 &button& 元素
Bootstrap 类解析
Bootstrap 类
table-striped
带条纹背景的表格
btn-success
glyphicon-pencil
glyphicon-user
glyphicon-save
form-horizontal
form-group
control-label
控制器标签
跨越 10 列
JavaScript 代码
myUsers.js
angular.module('myApp', []).controller('userCtrl',
function($scope) {$scope.fName
= '';$scope.lName = '';$scope.passw1 = '';$scope.passw2 = '';
$scope.users = [{id:1, fName:'Hege',&lName:"Pege" },
{id:2, fName:'Kim',&&lName:"Pim" },{id:3, fName:'Sal',&&lName:"Smith" },
{id:4, fName:'Jack',&lName:"Jones" },{id:5, fName:'John',&lName:"Doe"
},{id:6, fName:'Peter',lName:"Pan" }];$scope.edit = true;$scope.error = false;
$scope.incomplete = false; $scope.editUser =
function(id) {& if (id == 'new') {
&&& $scope.edit = true;&&& $scope.incomplete
= true;&&& $scope.fName = '';&&& $scope.lName
= '';&&& } else {&&& $scope.edit = false;&&& $scope.fName
= $scope.users[id-1].fN&&& $scope.lName
= $scope.users[id-1].lN & }};$scope.$watch('passw1',function()
{$scope.test();});$scope.$watch('passw2',function() {$scope.test();});
$scope.$watch('fName',&function() {$scope.test();});$scope.$watch('lName',&function() {$scope.test();});$scope.test = function() {& if
($scope.passw1 !== $scope.passw2) {&&& $scope.error =
true;&&& } else {&&& $scope.error =
false;& }& $scope.incomplete = false;& if ($scope.edit
&& (!$scope.fName.length ||& !$scope.lName.length ||&
!$scope.passw1.length || !$scope.passw2.length)) {&&&&&$scope.incomplete = true;& }};});
JavaScript 代码解析
Scope 属性
$scope.fName
模型变量 (用户名)
$scope.lName
模型变量 (用户姓)
$scope.passw1
模型变量 (用户密码 1)
$scope.passw2
模型变量 (用户密码 2)
$scope.users
模型变量 (用户的数组)
$scope.edit
当用户点击创建用户时设置为true。
$scope.error
如果 passw1 不等于 passw2 设置为 true
$scope.incomplete
如果每个字段都为空(length = 0)设置为 true
$scope.editUser
设置模型变量
$scope.watch
监控模型变量
$scope.test
验证模型变量的错误和完整性
反馈内容(*必填)
截图标记颜色
联系方式(邮箱)
联系邮箱:
投稿页面:
记住登录状态
重复输入密码深入理解AngularJs-Ui-router
Angularjs ui-router - 组件:
$state / $stateProvider:管理状态定义、当前状态和状态转换。包含触发状态转换的事件和回调函数,异步解决目标状态的任何依赖项,更新$location到当前状态。由于状态包含关联的 url,通过$urlRouterProvider生成一个路由规则来执行转换的状态。 ui-view指示器:渲染状态中定义的视图,是状态中定义的视图的一个占位符。 $urlRouter / $urlRouterProvider:管理了一套路由规则列表来处理当$location发生变化时如何跳转。最低级的方式是,规则可以是任意函数,来检查$location,并在处理完成时候返回true。支持正则表达式规则和通过$urlMatcherFactory编译的UrlMatcher对象的 url 占位符规则。 $urlMatcherFactory:将 url和占位符编译为UrlMatcher对象。除了$routeProvider支持的占位符语法之外,它还支持扩展语法,允许一个正则表达式指定占位符,并且能够提取命名参数和查询url的一部分。 $templateFactory - 通过$http / $templateCache来加载模板,供状态配置中使用。
AngularJS不需要任何第三方库,利用自身集成的各个模块便可开发出功能齐全的web应用,不过活跃的AngularJS社区也开发了很多能够最大限度强化web应用的库。本文带读者了解专业开发使用的模块AngularUI中的ui-路由(ui-router)。AngularUI库已经被分成了几个模块,用户可以只选择载入自己感兴趣的模块,而不用载入整个库。
UI-Router被认为是AngularUI为开发者提供的最实用的一个模块,它是一个让开发者能够根据URL状态或者说是&机器状态&来组织和控制界面UI的渲染,而不是仅仅只改变路由(传统AngularJS应用实用的方式)。该模块为开发者提供了很多最视图(view)额外的控制。开发者可以创建嵌套分层的视图、在同一个页面使用多个视图、让多个视图控制某个视图等更多的功能。即使是非常复杂的web应用,UI-Router也可以极佳地驾驭。
安装方式可以选择下载发行版本或者使用Bower(前端包管理器):
$ bower install angular-ui-router --save
同时也需要将源文件包含到页面中:
&script type=text/javascript src=app/bower_components/angular-ui-router/release/angular-ui-router.js&&/script&
接下来,将UI-Router作为web应用的依赖,注入到主程序:
angular.module('myApp', ['ui.router']);
与集成的ngRoute服务不同的是,UI-Router可以将视图嵌套,因为它基于的是操作状态而仅非URL。与传统做法使用ng-view不同的是,在ngRoute里需要使用ui-view服务。当在ui-router中处理路由和状态时,开发者的重心是当前的状态是什么以及在哪一个页面里。
和ngRoute一样,为特定状态指定的模板将会放在
元素中。在这些模板中也可以包含自己的ui-view,这就是在同一个路由下实现嵌套视图的方法。要定义一个路由,与传统的方法相同:使用.config方式,但使用的不是$routeProvider而是$stateProvider。
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('start', {
url: '/start',
templateUrl: 'partials/start.html'
上述代码在设置对象上定义了一个叫start的状态。设置对象stateConfig和路由设置对象的选项是非常相似的。
模板,模板路径,模板Provider
开发者可以在每个视图下使用如下方式来设置模板 - template - HTML字符串,或者是返回HTML字符串的函数 - templateUrl - HTML模板的路径,或者是返回HTML模板路径的函数 - templateProvider - 返回HTML字符串的函数 例如:
$stateProvider.state('home', {
template: '
Hello {{ name }}
和ngRoute相似,开发者可以指定任何已经被注册的控制器,或者在路由里面创建一个作为控制器的函数。但如果没有定义模板,控制器将无效。
预载入Resolve
使用预载入功能,开发者可以预先载入一系列依赖或者数据,然后注入到控制器中。在ngRoute中resolve选项可以允许开发者在路由到达前载入数据保证(promises)。在使用这个选项时比使用angular-route有更大的自由度。
预载入选项需要一个对象,这个对象的key即要注入到控制器的依赖,这个对象的value为需要被载入的factory服务。
如果传入的时字符串,angular-route会试图匹配已经注册的服务。如果传入的是函数,该函数将会被注入,并且该函数返回的值便是控制器的依赖之一。如果该函数返回一个数据保证(promise),这个数据保证将在控制器被实例化前被预先载入并且数据会被注入到控制器中。
$stateProvider.state('home', {
resolve: {
//这个函数的值会被直接返回,因为它不是数据保证
person: function() {
name: Ari,
email: ari@fullstack.io
//这个函数为数据保证, 因此它将在控制器被实例化之前载入。
currentDetails: function($http) {
return $http({
method: 'JSONP',
url: '/current_details'
//前一个数据保证也可作为依赖注入到其他数据保证中!(这个非常实用)
facebookId: function($http, currentDetails) {
method: 'GET',
url: '/api/current_user',
email: currentDetails.data.emails[0]
//定义控制器
controller: function($scope, person,
currentDetails, facebookId) {
$scope.person =
url选项将会为该应用的状态指定一个URL基于用户浏览该应用所在的状态。这样当在浏览该应用的时候便能实现深度链接的效果。 该选项与ngRoute的URL相似,但可以被视为对ngRoute主要的升级,在接下来的文章里你便会认可这一点。开发者可以这样指定一个基本的路由。
$stateProvider
.state('inbox', {
url: '/inbox',
template: '
Welcome to your inbox
当用户浏览到/inbox时,该应用将状态改为inbox同时向主ui-view元素中插入模板中的内容(&Welcome to your inbox&)。URL参数有多个选项,因此它非常强大。开发者可以像设置ngRoute一样设置最基本的参数:
$stateProvider
.state('inbox', {
url: '/inbox/:inboxId',
template: '
Welcome to your inbox
', controller: function($scope, $stateParams) { $scope.inboxId = $stateParams.inboxId; } });
现在将:inboxId最为URL的第二个部分,例如:访问/inbox/1,那么$stateParams.inboxId就为1($stateParams为{inboxId:1})。同时也可使用不同的语法:
url: '/inbox/{inboxId}'
路径必须匹配URL,与ngRoute不同的是,当用户访问到/inbox/时,上面的的路径会被激活,然而当访问到/inbox时不会被激活。路径同时也使开发者可以使用正则表达式来匹配,例如:
// 限定id为6位16进制数字
url: '/inbox/{inboxId:[0-9a-fA-F]{6}}',
// 匹配任何在 `/inbox`后面的url(慎用)并匹配值到indexId
url: '/inbox/{inboxId:.*}'
注意,在路由中目前还无法使用路由组,路由数据预载入器无法预载入。
在路径里也可以指定查询参数:
// /inbox?sort=ascending 将会被匹配
url: '/inbox?sort'
使用url参数可以实现嵌套的路由,有了嵌套路由便可在同一个模板同一个路由实现多层次的ui-view,例如在/inbox中嵌入更多路由:
$stateProvider
.state('inbox', {
url: '/inbox/:inboxId',
template: '
Welcome to your inbox
', controller: function($scope, $stateParams) { $scope.inboxId = $stateParams.inboxId; } }) .state('inbox.priority', { url: '/priority', template: '
Your priority inbox
第一个路由是传统的,注意第二个,它是/inbox下的一个子路由:state( . )语法指定了它使子路由。/inbox/1将匹配第一个路由,而/index/1/priority会匹配第二个路由。使用这种语法,在父视图中的ui-view元素将会由第二个路由控制。
Params 路由参数
params选项是一个包含路径中的参数和正则表达式匹配结果的数组。该选项不能和url选项混用!当某状态被激活时,应用将这个数组赋值给$stateParams服务。
Views 视图
开发者可以在一个状态中设置多个有名称的视图。该功能在ui-router中很强大,开发者可以在同一个模板中改变和切换不同的视图。
&如果设置了视图选项,则该状态的&template&,&templateUrl&及&templateProvider&将被忽略。如果想在路由里包含父级模板,就需要创建一个包含模板的抽象模板。
例如有这样的视图:
接下来就可以创建将被分别被插入到上述ui-view的有命名的视图了,每个子视图可以包含自己的模板、控制器和预载入数据。
$stateProvider
.state('inbox', {
'filters': {
template: '
Filter inbox
', controller: function($scope) {} }, 'mailbox': { templateUrl: 'partials/mailbox.html' }, 'priority': { template: '
Priority inbox
', resolve: { facebook: function() { return FB.messages(); } } } } });
abstract 抽象模板
抽象模板不能被激活,但是它的子模板可以被激活。抽象模板可以提供一个包括了多个有名的视图的模板,或者它可以传递作用域变量$scope给子模板。使用它可以在同一个url下传递自定义数据或者预载入的依赖。除了需要添加abstract属性外,其他设置和设定一个常规状态是相同的:
$stateProvider
.state('admin', {
abstract: true,
url: '/admin',
template: '
' }) .state('admin.index', { url: '/index', template: '
Admin index
' }) .state('admin.users', { url: '/users', template: '
onEnter,onExit 回调函数
当应用进入或者离开当前状态的视图时会调用这两个函数。这两个函数可以访问预载入的数据。这两个回调函数使开发者可以根据状态改变来采取某些动作,例如在用户要离开时可以弹出对话框&你确定吗?&以及防止意外操作等。
自定义数据也可以被附加到状态控制对象state configObject.该数据和预载入数据resolve属性相似,但是该数据不会被注入到控制器中,promise也不会被预载入,它的用途是从父状态传递数据到子状态。
和ngRoute相同的是,angular-route服务会在不同的状态生命周期lifecycle里启动某些事件events。监听$scope对象便可以捕获这些事件然后采取不同的响应或者操作。如下的事件将会在$rootScope上触发,因此在任何$scope对象上都可以监听到这些事件。
状态改变事件
$scope.$on('$stateChangeStart',
function(evt, toState, toParams, fromState, fromParams), {
// 如果需要阻止事件的完成
evt.preventDefault();
可以触发的事件包括:
stateChangeStart
当状态改变开始的时候被触发
$stateChangeSuccess
当状态改变成功后被触发
$stateChangeError
当状态改变遇到错误时被触发,错误通常是目标无法载入,需要预载入的数据无法被载入等。
视图载入事件
视图载入阶段ui-router也提供了一些事件
$viewContentLoading
当视图正在被载入且在DOM被渲染之前触发。
$scope.$on('$viewContentLoading',
function(event, viewConfig){
// 获取任何视图设置的参数,以及一个特殊的属性:viewConfig.targetView
$viewContentLoaded
当视图被载入且DOM已经渲染完成后被触发。
$stateParams 状态参数
在上面提及使用$stateparams来提取在url中的不同参数。该服务的作用是处理url的不同部分。例如,当上述的inbox状态是这样时:
url: '/inbox/:inboxId/messages/{sorted}?from&to'
//当用户访问者链接时:
'/inbox/123/messages/ascending?from=10&to=20'
$stateParams对象的值为:
{inboxId: '123', sorted: 'ascending', from: 10, to: 20}
$urlRouterProvider
和ngRoute一样,开发者可以在该对象上设定特定的URL被激活时做什么的规则。由于设定好的状态在特定的url被访问是会自动激活,所以$urlRouterProvider没有必要用来管理激活和载入状态。但当需要管理哪些被发生在当前状态之外的作用域scope时它会非常有用,例如在重定向或者安全验证的时候。在模块的设置函数里便可使用$urlRouterProvider。
该函数需要两个参数:1.当前的路径,2.需要重定向到的路径(或者是需要在路径被访问是运行的函数)。设置重定向前需要为$urlRouterProvider设置when函数来接受一个字符串。例如,当希望重定向一个空的路由到/inbox:
.config(function($urlRouterProvider) {
$urlRouterProvider.when('', '/inbox');
如果传递的是函数,在路径被匹配时该函数会被执行,处理器返回如下3个值中的一个: - falsy,该回应告诉$urlRouter没有匹配到当前url规则,应该尝试匹配新的路径,这样能保证用户访问了正常的路径。 - 字符串,$urlRouter将该字符串当做重定向的路径。 - TRUE 或者 undefined,该回应告诉$urlRouter,url已被处理
otherwise()
和ngRoute的otherwise()函数相似,在用户提交的路径没有被定义的时候它将重定向到指定的页面。这是个创建&默认&路径的好方法。 otherwise()只接受一个参数,要么函数要么字符串,字符串必须为合法的url路由地址,函数则会在没有任何路径被匹配的时候被运行。
.config(function($urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$urlRouterProvider.otherwise(
function($injector, $location) {
$location.path('/');
如果想越过任何URL的匹配或者在其他路由前做路由修改,则可以使用rule()函数。在使用它的时候必须返回一个合法的代表路径的字符串。
app.config(function($urlRouterProvider){
$urlRouterProvider.rule(
function($injector, $location) {
return '/index';
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'Angular-UI手风琴效果源码分析 - 简书
Angular-UI手风琴效果源码分析
* angular-ui-bootstrap
* http://angular-ui.github.io/bootstrap/
* Version: 0.14.3 -
* License: MIT
angular.module("ui.bootstrap", ["ui.bootstrap.tpls","ui.bootstrap.accordion","ui.bootstrap.collapse"]);
angular.module("ui.bootstrap.tpls", ["template/accordion/accordion-group.html","template/accordion/accordion.html"]);
angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
.constant('uibAccordionConfig', {//constant 可以将一个已经存在的变量值注册为服务
closeOthers: true
.controller('UibAccordionController', ['$scope', '$attrs', 'uibAccordionConfig', function($scope, $attrs, accordionConfig) {
// This array keeps track of the accordion groups
this.groups = [];//用数组来保存所有的手风琴组
// Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to //确保所有的手风琴组是关闭的,除非其它关闭的并不是
this.closeOthers = function(openGroup) { //关闭函数 如果oneAtATime存在且为true
var closeOthers = angular.isDefined($attrs.closeOthers) ?
$scope.$eval($attrs.closeOthers) : accordionConfig.closeO//判断$attrs.closeOthers是否定义过
if (closeOthers) {
angular.forEach(this.groups, function(group) { //遍历所有的手风琴组
if (group !== openGroup) { //如果没有规定打开的手风琴组,就全部关闭
group.isOpen =
// This is called from the accordion-group directive to add itself to the accordion //要向手风琴组添加对象时调用的函数
this.addGroup = function(groupScope) { //添加的是作用域
var that =
this.groups.push(groupScope);
groupScope.$on('$destroy', function(event) {//当监听到销毁,就移除手风琴组
that.removeGroup(groupScope);
// This is called from the accordion-group directive when to remove itself //要移除手风琴组时候调用,需要移除数组中对应的项
this.removeGroup = function(group) {
var index = this.groups.indexOf(group);
if (index !== -1) {
this.groups.splice(index, 1);
// The accordion directive simply sets up the directive controller 这个指令只是建立了这个指令的控制器和添加了一个css类型
// and adds an accordion CSS class to itself element.
//&uib-accordion close-others="oneAtATime"&
&/uib-accordion& 对应指令 模板&div class=\"panel-group\" ng-transclude&&/div&
.directive('uibAccordion', function() {
controller: 'UibAccordionController',
controllerAs: 'accordion',//控制器别名
transclude: true,//可以替换
templateUrl: function(element, attrs) { //
return attrs.templateUrl || 'template/accordion/accordion.html';
// The accordion-group directive indicates a block of html that will expand and collapse in an
这个指令表示出一段html展开或者折叠在一个手风琴效果中
// &uib-accordion-group heading="Static Header, initially expanded" is-open="status.isFirstOpen" is-disabled="status.isFirstDisabled"&This content is straight in the template. &/uib-accordion-group&
.directive('uibAccordionGroup', function() {
require: '^uibAccordion',
// We need this directive to be inside an accordion //我们需要这个指令来在其中放入一个手风琴效果
transclude: true,
// It transcludes the contents of the directive into the template 允许这个指令的内容到模板中进行替换
replace: true,
// The element containing the directive will be replaced with the template
templateUrl: function(element, attrs) { //调用模板
return attrs.templateUrl || 'template/accordion/accordion-group.html';
heading: '@',
// Interpolate the heading attribute onto this scope //传递的是字符串
isOpen: '=?', //=双向绑定
isDisabled: '=?' //?告诉指令如果没有找到依赖的指令,不要抛出异常。
controller: function() { //设置当前对象的heading
this.setHeading = function(element) {
this.heading =
link: function(scope, element, attrs, accordionCtrl) {
accordionCtrl.addGroup(scope);//把当前scope添加进 手风琴数组
scope.openClass = attrs.openClass || 'panel-open';//展开的样式
scope.panelClass = attrs.panelC//获取具体定义的类名
scope.$watch('isOpen', function(value) {//监听isOpen,判断是否发生变化
element.toggleClass(scope.openClass, !!value);//如果isOpen为ture时,就添加展开的样式
if (value) {
accordionCtrl.closeOthers(scope);
scope.toggleOpen = function($event) { //手风琴开关函数
if (!scope.isDisabled) { //scope.isDisabled为false时执行
if (!$event || $event.which === 32) {
scope.isOpen = !scope.isO
// Use accordion-heading below an accordion-group to provide a heading containing HTML
//使用手风琴标题下面的手风琴组,提供一个内容标签
//对应指令 &uib-accordion-heading& I can have markup, too! &i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': status.open, 'glyphicon-chevron-right': !status.open}"&&/i& &/uib-accordion-heading&
.directive('uibAccordionHeading', function() {
transclude: true,
// Grab the contents to be used as the heading
template: '',
// In effect remove this element!
replace: true,
require: '^uibAccordionGroup',
link: function(scope, element, attrs, accordionGroupCtrl, transclude) {
// Pass the heading to the accordion-group controller
// so that it can be transcluded into the right place in the template
// [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
accordionGroupCtrl.setHeading(transclude(scope, angular.noop));
// Use in the accordion-group template to indicate where you want the heading to be transcluded
// You must provide the property on the accordion-group controller that will hold the transcluded element
//&a href tabindex="0" class="accordion-toggle" ng-click="toggleOpen()" uib-accordion-transclude="heading"&&span ng-class="{'text-muted': isDisabled}"&{{heading}}&/span&&/a&
.directive('uibAccordionTransclude', function() {
require: ['?^uibAccordionGroup', '?^accordionGroup'],
link: function(scope, element, attrs, controller) {
controller = controller[0] ? controller[0] : controller[1]; // Delete after we remove deprecation
scope.$watch(function() { return controller[attrs.uibAccordionTransclude]; }, function(heading) {//{{heading}}
if (heading) {
element.find('span').html('');
element.find('span').append(heading);
/* Deprecated accordion below
//弃用的手风琴 dead code
angular.module('ui.bootstrap.accordion')
.value('$accordionSuppressWarning', false)
.controller('AccordionController', ['$scope', '$attrs', '$controller', '$log', '$accordionSuppressWarning', function($scope, $attrs, $controller, $log, $accordionSuppressWarning) {
if (!$accordionSuppressWarning) {
$log.warn('AccordionController is now deprecated. Use UibAccordionController instead.');
angular.extend(this, $controller('UibAccordionController', { //扩展当前控制器
$scope: $scope,
$attrs: $attrs
})); //加载控制器并传入一个作用域,同AngularJS在运行时做的一样
.directive('accordion', ['$log', '$accordionSuppressWarning', function($log, $accordionSuppressWarning) {
restrict: 'EA',
controller: 'AccordionController',
controllerAs: 'accordion', //控制器别名
transclude: true,
replace: false,
templateUrl: function(element, attrs) {
return attrs.templateUrl || 'template/accordion/accordion.html';//替换成 &div class=\"panel-group\" ng-transclude&&/div&
link: function() {
if (!$accordionSuppressWarning) {
$log.warn('accordion is now deprecated. Use uib-accordion instead.');
.directive('accordionGroup', ['$log', '$accordionSuppressWarning', function($log, $accordionSuppressWarning) {
require: '^accordion',
// We need this directive to be inside an accordion
restrict: 'EA',
transclude: true,
// It transcludes the contents of the directive into the template
replace: true,
// The element containing the directive will be replaced with the template
templateUrl: function(element, attrs) {
return attrs.templateUrl || 'template/accordion/accordion-group.html';
heading: '@',
//传递字符串值
// Interpolate the heading attribute onto this scope
isOpen: '=?',
//=双向绑定
isDisabled: '=?'
//=双向绑定
controller: function() { //让这个指令的heading等于传入的参数
this.setHeading = function(element) {
this.heading =
link: function(scope, element, attrs, accordionCtrl) {
if (!$accordionSuppressWarning) {
$log.warn('accordion-group is now deprecated. Use uib-accordion-group instead.');
accordionCtrl.addGroup(scope);
scope.openClass = attrs.openClass || 'panel-open';
scope.panelClass = attrs.panelC
scope.$watch('isOpen', function(value) {
element.toggleClass(scope.openClass, !!value);
if (value) {
accordionCtrl.closeOthers(scope);
scope.toggleOpen = function($event) {
if (!scope.isDisabled) {
if (!$event || $event.which === 32) {
scope.isOpen = !scope.isO
.directive('accordionHeading', ['$log', '$accordionSuppressWarning', function($log, $accordionSuppressWarning) {
restrict: 'EA',
transclude: true,
// Grab the contents to be used as the heading
template: '',
// In effect remove this element!
replace: true,
require: '^accordionGroup',
link: function(scope, element, attr, accordionGroupCtrl, transclude) {
if (!$accordionSuppressWarning) {
$log.warn('accordion-heading is now deprecated. Use uib-accordion-heading instead.');
// Pass the heading to the accordion-group controller
// so that it can be transcluded into the right place in the template
// [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
accordionGroupCtrl.setHeading(transclude(scope, angular.noop));
.directive('accordionTransclude', ['$log', '$accordionSuppressWarning', function($log, $accordionSuppressWarning) {
require: '^accordionGroup',
link: function(scope, element, attr, controller) {
if (!$accordionSuppressWarning) {
$log.warn('accordion-transclude is now deprecated. Use uib-accordion-transclude instead.');
scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) {
if (heading) {
element.find('span').html('');
element.find('span').append(heading);
//具体内容展示模块,没有独立scope,与父级使用同一个scope
angular.module('ui.bootstrap.collapse', [])
//&div class="panel-collapse collapse" uib-collapse="!isOpen"&的指令
.directive('uibCollapse', ['$animate', '$injector', function($animate, $injector) {
var $animateCss = $injector.has('$animateCss') ? $injector.get('$animateCss') ://判断是否有$animateCss服务注入,如果有就取得这个服务
link: function(scope, element, attrs) {//link函数
//展开函数
function expand() {
element.removeClass('collapse')
.addClass('collapsing')
.attr('aria-expanded', true)//aria-expanded表示展开状态。默认为undefined, 表示当前展开状态未知。这里表示展开
.attr('aria-hidden', false);//这里表示关闭
if ($animateCss) {//如果有$animateCss服务,就用来添加动画
$animateCss(element, {
addClass: 'in',//in样式就是block
easing: 'ease',
to: { height: element[0].scrollHeight + 'px' }
}).start().finally(expandDone);
} else {//如果没有就用ng自带的动画模块
$animate.addClass(element, 'in', {
to: { height: element[0].scrollHeight + 'px' }
}).then(expandDone);//返回一个promise对象,用then来处理成功回调
//展开后回调
function expandDone() {//具体的成功回调函数,用来操作class
element.removeClass('collapsing')
.addClass('collapse')//display:none
.css({height: 'auto'});
//收缩函数
function collapse() {
if (!element.hasClass('collapse') && !element.hasClass('in')) {//如果element没有collapse样式,并且也没有in样式
return collapseDone();
// IMPORTANT: The height must be set before adding "collapsing" class.
// Otherwise, the browser attempts to animate from height 0 (in
// collapsing class) to the given height here.
.css({height: element[0].scrollHeight + 'px'}) //设置高度
// initially all panel collapse have the collapse class, this removal
// prevents the animation from jumping to collapsed state
.removeClass('collapse') //移除collapse,也就是移除display:none
.addClass('collapsing')
//添加collapsing,高度0
.attr('aria-expanded', false)
.attr('aria-hidden', true);
if ($animateCss) {
$animateCss(element, {
removeClass: 'in',
to: {height: '0'}
}).start().finally(collapseDone);
$animate.removeClass(element, 'in', {//设置动画,高度为0
to: {height: '0'}
}).then(collapseDone);
//收缩后回调函数
function collapseDone() {
element.css({height: '0'}); // Required so that collapse works when animation is disabled 动画不执行时运行
element.removeClass('collapsing')//collapsing设置高度为0
.addClass('collapse');//display:none
//监听attrs.uibCollapse也就是!isOpen的值,来判断展开和关闭
scope.$watch(attrs.uibCollapse, function(shouldCollapse) {
if (shouldCollapse) {
collapse();
/* Deprecated collapse below
angular.module('ui.bootstrap.collapse')
.value('$collapseSuppressWarning', false)
.directive('collapse', ['$animate', '$injector', '$log', '$collapseSuppressWarning', function($animate, $injector, $log, $collapseSuppressWarning) {
var $animateCss = $injector.has('$animateCss') ? $injector.get('$animateCss') :
link: function(scope, element, attrs) {
if (!$collapseSuppressWarning) {
$log.warn('collapse is now deprecated. Use uib-collapse instead.');
function expand() {
element.removeClass('collapse')
.addClass('collapsing')
.attr('aria-expanded', true)
.attr('aria-hidden', false);
if ($animateCss) {
$animateCss(element, {
easing: 'ease',
to: { height: element[0].scrollHeight + 'px' }
}).start().done(expandDone);
$animate.animate(element, {}, {
height: element[0].scrollHeight + 'px'
}).then(expandDone);
function expandDone() {
element.removeClass('collapsing')
.addClass('collapse in')
.css({height: 'auto'});
function collapse() {
if (!element.hasClass('collapse') && !element.hasClass('in')) {
return collapseDone();
// IMPORTANT: The height must be set before adding "collapsing" class.
// Otherwise, the browser attempts to animate from height 0 (in
// collapsing class) to the given height here.
.css({height: element[0].scrollHeight + 'px'})
// initially all panel collapse have the collapse class, this removal
// prevents the animation from jumping to collapsed state
.removeClass('collapse in')
.addClass('collapsing')
.attr('aria-expanded', false)
.attr('aria-hidden', true);
if ($animateCss) {
$animateCss(element, {
to: {height: '0'}
}).start().done(collapseDone);
$animate.animate(element, {}, {
height: '0'
}).then(collapseDone);
function collapseDone() {
element.css({height: '0'}); // Required so that collapse works when animation is disabled
element.removeClass('collapsing')
.addClass('collapse');
scope.$watch(attrs.collapse, function(shouldCollapse) {
if (shouldCollapse) {
collapse();
angular.module("template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("template/accordion/accordion-group.html",
"&div class=\"panel {{panelClass || 'panel-default'}}\"&\n" +
&div class=\"panel-heading\" ng-keypress=\"toggleOpen($event)\"&\n" +
&h4 class=\"panel-title\"&\n" +
&a href tabindex=\"0\" class=\"accordion-toggle\" ng-click=\"toggleOpen()\" uib-accordion-transclude=\"heading\"&&span ng-class=\"{'text-muted': isDisabled}\"&{{heading}}&/span&&/a&\n" +
&/h4&\n" +
&/div&\n" +
&div class=\"panel-collapse collapse\" uib-collapse=\"!isOpen\"&\n" +
&div class=\"panel-body\" ng-transclude&&/div&\n" +
&/div&\n" +
"&/div&\n" +
angular.module("template/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("template/accordion/accordion.html",
"&div class=\"panel-group\" ng-transclude&&/div&");
&div ng-controller="AccordionDemoCtrl"&
&script type="text/ng-template" id="group-template.html"&
&div class="panel {{panelClass || 'panel-default'}}"&
&div class="panel-heading"&
&h4 class="panel-title" style="color:#fa39c3"&
&a href tabindex="0" class="accordion-toggle" ng-click="toggleOpen()" uib-accordion-transclude="heading"&&span
ng-class="{'text-muted': isDisabled}"&{{heading}}&/span&&/a&
&div class="panel-collapse collapse" uib-collapse="!isOpen"&
&div class="panel-body" style="text-align: right" ng-transclude&&/div&
&button type="button" class="btn btn-default btn-sm" ng-click="status.open = !status.open"&Toggle last panel&/button&
&button type="button" class="btn btn-default btn-sm" ng-click="status.isFirstDisabled = ! status.isFirstDisabled"&Enable / Disable first panel&/button&
&div class="checkbox"&
&input type="checkbox" ng-model="oneAtATime"&
Open only one at a time
&uib-accordion close-others="oneAtATime"&
&uib-accordion-group heading="Static Header, initially expanded" is-open="status.isFirstOpen" is-disabled="status.isFirstDisabled"&
This content is straight in the template.
&/uib-accordion-group&
&uib-accordion-group heading="{{group.title}}" ng-repeat="group in groups"&
{{group.content}}
&/uib-accordion-group&
&uib-accordion-group heading="Dynamic Body Content"&
&p&The body of the uib-accordion group grows to fit the contents&/p&
&button type="button" class="btn btn-default btn-sm" ng-click="addItem()"&Add Item&/button&
&div ng-repeat="item in items"&{{item}}&/div&
&/uib-accordion-group&
&uib-accordion-group heading="Custom template" template-url="group-template.html"&
&/uib-accordion-group&
&uib-accordion-group heading="Delete account" panel-class="panel-danger"&
&p&Please, to delete your account, click the button below&/p&
&button class="btn btn-danger"&Delete&/button&
&/uib-accordion-group&
&uib-accordion-group is-open="status.open"&
&uib-accordion-heading&
I can have markup, too! &i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': status.open, 'glyphicon-chevron-right': !status.open}"&&/i&
&/uib-accordion-heading&
This is just some content to illustrate fancy headings.
&/uib-accordion-group&
&/uib-accordion&
angular.module('ui.bootstrap.demo').controller('AccordionDemoCtrl', function ($scope) {
$scope.oneAtATime =
$scope.groups = [
title: 'Dynamic Group Header - 1',
content: 'Dynamic Group Body - 1'
title: 'Dynamic Group Header - 2',
content: 'Dynamic Group Body - 2'
$scope.items = ['Item 1', 'Item 2', 'Item 3'];
$scope.addItem = function() {
var newItemNo = $scope.items.length + 1;
$scope.items.push('Item ' + newItemNo);
$scope.status = {
isFirstOpen: true,
isFirstDisabled: false
第一部分是angular插件的源码,后面是官网的示例(插件最核心的就是实现不同指令间的通信,这个插件实现的方式是让两个作用域,UibAccordionController和uibCollapse这两个控制器下的作用域下的实现通信。通信的方式是利用父子指令间,通过scope继承实现的。分别继承(双向绑定)heading\isOpen\isDisabled三个参数。然后在分别的指令中对isOpen进行监听,就可以得到不同的效果。
前端路上。。。。

我要回帖

更多关于 lsmodels系列是什么 的文章

 

随机推荐