在这些函数调用之间还会发生什么?
不同的指令函数是在另外两个angular函数$compile(指令的编译函数在这里执行)和一个内部函数nodeLinkFn(指令的控制器、preLink和postLink在这里执行)中执行的。在调用指令函数之前和之后,angular函数中会发生各种事情。也许最值得注意的是子递归。下面的简化图显示了编译和链接阶段的关键步骤:
为了演示这些步骤,让我们使用下面的HTML标记:
<div ng-repeat="i in [0,1,2]">
<my-element>
<div>Inner content</div>
</my-element>
</div>
使用以下指令:
myApp.directive( 'myElement', function() {
return {
restrict: 'EA',
transclude: true,
template: '<div>{{label}}<div ng-transclude></div></div>'
}
});
编译
编译API看起来像这样:
compile: function compile( tElement, tAttributes ) { ... }
参数通常以t作为前缀,表示所提供的元素和属性是源模板的元素和属性,而不是实例的元素和属性。
在删除编译被传输内容(如果有的话)的调用,并将模板应用于标记之前。因此,提供给compile函数的元素将如下所示:
<my-element>
<div>
"{{label}}"
<div ng-transclude></div>
</div>
</my-element>
请注意,此时未重新插入所传输的内容。
在调用指令的.compile之后,Angular将遍历所有子元素,包括那些指令刚刚引入的元素(例如模板元素)。
实例创建
在我们的例子中,将创建上述源模板的三个实例(通过ng-repeat)。因此,下面的序列将执行三次,每个实例一次。
控制器
控制器API包括:
controller: function( $scope, $element, $attrs, $transclude ) { ... }
进入链接阶段,通过$compile返回的链接函数现在具有作用域。
首先,如果被请求,link函数创建一个子作用域(scope: true)或一个隔离作用域(scope:{…})。
然后执行控制器,并提供实例元素的作用域。
预链接
预链接API如下所示:
function preLink( scope, element, attributes, controller ) { ... }
实际上,在调用指令的.controller和. prelink函数之间没有发生任何事情。Angular仍然提供了如何使用它们的建议。
在. prelink调用之后,link函数将遍历每个子元素——调用正确的link函数并将当前作用域(用作子元素的父作用域)附加到它。
Post-link
post-link API类似于pre-link函数:
function postLink( scope, element, attributes, controller ) { ... }
也许值得注意的是,一旦一个指令的. postlink函数被调用,它所有子元素的链接过程就完成了,包括所有子元素的. postlink函数。
这意味着在调用. postlink时,子进程已经“活”了。这包括:
数据绑定
transclusion应用
范围在
这个阶段的模板看起来是这样的:
<my-element>
<div class="ng-binding">
"{{label}}"
<div ng-transclude>
<div class="ng-scope">Inner content</div>
</div>
</div>
</my-element>