源码先放在这里,以后来补充,大部分注释写了,很好明白。
/*
* angular-ui-bootstrap
* http://angular-ui.github.io/bootstrap/
* Version: 1.2.4 - 2016-03-06
* License: MIT
*/angular.module("ui.bootstrap", ["ui.bootstrap.tpls","ui.bootstrap.collapse"]);
angular.module("ui.bootstrap.tpls", []);
angular.module('ui.bootstrap.collapse', [])
.directive('uibCollapse', ['$animate', '$q', '$parse', '$injector', function($animate, $q, $parse, $injector) {
var $animateCss = $injector.has('$animateCss') ? $injector.get('$animateCss') : null;
return {
link: function(scope, element, attrs) {
var expandingExpr = $parse(attrs.expanding),//假如指令属性中有expanding方法,则用$attr获取
expandedExpr = $parse(attrs.expanded),//假如属性中有expanded方法,则用$attr获取
collapsingExpr = $parse(attrs.collapsing),//假如属性中有collapsingExpr方法,则用$attr获取
collapsedExpr = $parse(attrs.collapsed);//假如属性中有collapsedExpr方法,则用$attr获取
//$parse和$eval都是解析字符串,区别是$parse是作为单独的一个服务存在,$eval是作为单独的一个scope方法来使用的
if (!scope.$eval(attrs.uibCollapse)) {//如果uib-collapse为false的话,就为元素添加如下样式和属性
element.addClass('in')
.addClass('collapse')
.attr('aria-expanded', true)
.attr('aria-hidden', false)
.css({height: 'auto'});
}
//展开方法,由shouldCollapse负责监听,并且通过$q来达到展开折叠前后事件发生的控制
function expand() {
if (element.hasClass('collapse') && element.hasClass('in')) { //如果已经是展开的就返回
return;
}
//查到的资料显示 resolve是$q.deffer()的方法,不知这里为什么$q怎么回事。
$q.resolve(expandingExpr(scope))//成功执行的信息,传递下去
.then(function() {
element.removeClass('collapse')
.addClass('collapsing')
.attr('aria-expanded', true)
.attr('aria-hidden', false);
if ($animateCss) {
$animateCss(element, {
addClass: 'in',
easing: 'ease',
to: { height: element[0].scrollHeight + 'px' }
}).start()['finally'](expandDone);
} else {
$animate.addClass(element, 'in', {
to: { height: element[0].scrollHeight + 'px' }
}).then(expandDone);
}
});
}
function expandDone() {
element.removeClass('collapsing')
.addClass('collapse')
.css({height: 'auto'});
expandedExpr(scope);
}
function collapse() {
if (!element.hasClass('collapse') && !element.hasClass('in')) {
return collapseDone();
}
$q.resolve(collapsingExpr(scope))
.then(function() {
element
// 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')
.addClass('collapsing')
.attr('aria-expanded', false)
.attr('aria-hidden', true);
if ($animateCss) {
$animateCss(element, {
removeClass: 'in',
to: {height: '0'}
}).start()['finally'](collapseDone);
} else {
$animate.removeClass(element, 'in', {
to: {height: '0'}
}).then(collapseDone);
}
});
}
function collapseDone() {
element.css({height: '0'}); // Required so that collapse works when animation is disabled
element.removeClass('collapsing')
.addClass('collapse');
collapsedExpr(scope);
}
//监听展开折叠变化
scope.$watch(attrs.uibCollapse, function(shouldCollapse) {
if (shouldCollapse) {
collapse();
} else {
expand();
}
});
}
};
}]);