Angular指令执行流程

流程概览

整个流程分为两个阶段:$compile 和 nodeLinkFn

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//总体流程
// 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)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//例子
<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>'
}
});
  1. 首先进入$compile。其中tElement和tAttributes为指令传入的属性。如果指令内部有嵌套的子指令(如ng-repeat),
    则会遍历调用所有子指令的compile。在我们的例子里,三个子source template(通过ng-repeat)会被创建,所以compile会调用一共4次。

    1
    2
    //一个compile函数API类似
    compile: function compile( tElement, tAttributes ) { ... }
  2. 接下来进入nodeLinkFn阶段(link阶段)。经由$compile返回的link函数被提供一个scope。
    首先link函数创建一个子scope(scope:true),或者一个隔离作用域(scope:{…})。接着执行controller函数,传入scope。

    1
    2
    //一个controller函数API类似
    controller: function controller($scope, $element, $attrs,$transclude ) { ... }
  3. 接下来进入pre-link阶段,基本上在controller和preLink之间不会执行其他函数。在父级preLink被调用,紧接着会遍历调用子级preLink。

    1
    2
    //一个preLink函数API类似
    preLink: function preLink(scope, element, attrs,controller ) { ... }
1
2
//postLink与preLink API类似
postLink: function postLink(scope, element, attrs,controller ) { ... }

注意当一个
子级preLink函数执行完后会继续执行该子子级的postLink函数,接着再执行下一个子级的preLink与postLink。也就说当父级执行postLink时,其所有子级的link函数都已执行完毕。这意味着子级已经完成:

  • 数据绑定
  • transclusion已经应用
  • scope形成
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //这个阶段的DOM结构看起来如下
    <my-element>
    <div class="ng-binding">
    "{{label}}"
    <div ng-transclude>
    <div class="ng-scope">Inner content</div>
    </div>
    </div>
    </my-element>