指令函数的执行顺序是什么?
对于单个指令
基于以下内容,考虑以下HTML标记:
<body>
<div log='some-div'></div>
</body>
使用以下指令声明:
myApp.directive('log', function() {
return {
controller: function( $scope, $element, $attrs, $transclude ) {
console.log( $attrs.log + ' (controller)' );
},
compile: function compile( tElement, tAttributes ) {
console.log( tAttributes.log + ' (compile)' );
return {
pre: function preLink( scope, element, attributes ) {
console.log( attributes.log + ' (pre-link)' );
},
post: function postLink( scope, element, attributes ) {
console.log( attributes.log + ' (post-link)' );
}
};
}
};
});
控制台输出将是:
some-div (compile)
some-div (controller)
some-div (pre-link)
some-div (post-link)
我们可以看到compile首先执行,然后是controller,然后是pre-link,最后是post-link。
对于嵌套指令
注意:以下内容不适用于在link函数中呈现子函数的指令。相当多的Angular指令是这样做的(比如ngIf、ngRepeat或任何带有transclude的指令)。在调用这些指令的子指令compile之前,这些指令本身就已经调用了它们的链接函数。
原始的HTML标记通常由嵌套的元素组成,每个元素都有自己的指令。就像下面的标记(见plunk):
<body>
<div log='parent'>
<div log='..first-child'></div>
<div log='..second-child'></div>
</div>
</body>
控制台输出如下所示:
// The compile phase
parent (compile)
..first-child (compile)
..second-child (compile)
// The link phase
parent (controller)
parent (pre-link)
..first-child (controller)
..first-child (pre-link)
..first-child (post-link)
..second-child (controller)
..second-child (pre-link)
..second-child (post-link)
parent (post-link)
这里我们可以区分两个阶段——编译阶段和链接阶段。
编译阶段
当加载DOM时,Angular会启动编译阶段,在这个阶段,它会自顶向下遍历标记,并对所有指令调用compile。从图形上来说,我们可以这样表达:
值得一提的是,在此阶段,compile函数获得的模板是源模板(而不是实例模板)。
链接阶段
DOM实例通常只是一个源模板被呈现给DOM的结果,但是它们可能是由ng-repeat创建的,或者是动态引入的。
每当一个带有指令的元素的新实例被呈现给DOM时,链接阶段就开始了。
在这个阶段,Angular会对所有指令调用controller、pre-link、迭代子函数和post-link,如下所示: