AngularJS 的 directive机制

指令的定义

指令可以理解为在特定的 DOM 元素上运行的函数,指令可以扩展元素的功能。使用这个机制我们可以模块化我们的代码。以实现更好的结构和代码复用。

指令作用域

scope

scope 属性设置为 true 的话,则表示指令创建了一个继承自父作用域的新作用域对象。
设置为 false 则表示不创建作用域。

scope 也可以被设置为一个对象,当设置为一个对象的时候表示指令创建了一个隔离作用域,这个作用域是与外部完全无关的,干净的环境。通过绑定策略可以使隔离作用域与父作用域进行交互。

隔离作用域

当 scope 被设置为一个对象的时候,表示指令内部声明了一个隔离作用域,这个作用域对象与外部完全无关,不能访问外部作用域的任何东西,是一个干净的环境。通过绑定策略可以使隔离作用域与父作用域进行交互。

Demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--指令作用域-->
<div ng-controller="DirectiveScopeController">
<!--继承作用域-->
<div ng-init="outData1='Hello World!'">
1:{{outData1}}
<div my-inherit-scope-directive>

</div>
</div>
<!--隔离作用域-->
<div ng-init="outData2='Hello World!'">
1:{{outData2}}
<div my-isolate-scope-directive>
</div>
<div my-isolate-scope-directive2>
</div>
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
app.directive('myInheritScopeDirective', function () {
return {
restrict: 'A',
replace: true,
template:"<p>this is 2: {{outData1}}",
scope:true
}
})

app.directive('myIsolateScopeDirective', function () {
return {
restrict: 'A',
replace: true,
template:"<p>this is 2: {{outData2}}</p>",
scope:{}
}
}).directive('myIsolateScopeDirective2', function () {
return {
restrict: 'A',
replace: true,
template:"<p>this is 2: {{outData2}}</p>",
scope:true
}
});

app.controller("DirectiveScopeController", function () {

});

上述代码中也反映了数据的绑定方式:html 中的模型在 scope 中绑定给 scope 作用域变量。然后在 directive 中使用作用域变量来为模板赋值。对于表达式字符串使用"@"绑定;对于对象使用"="绑定;对于函数使用"&"进行绑定

绑定策略

绑定策略有三种形式,分别是@=&
@: 字符串(表达式)绑定
=: 对象绑定
&: 函数绑定

AngularJS 生命周期

编译阶段

这是 Anguar 生命周期的第一个阶段,这个阶段 Angular 会遍历整个 HTML 文档并根据 JS 中指令的定义来处理页面上声明的指令。指令的模板也可能会包含带有模板的指令,模板树可能会变得又大又深。但是注意只有优先级最高的指令的模板才会被解析并添加到模板树中所以最佳实践是:永远不要在一个一个元素中使用一个以上的指令对其修饰)。编译后的模板会返回一个模板函数。在模板函数返回之前我们仍然有机会对编译后的 DOM 树进行修改。这个时候 DOM 树还没有进行数据绑定所以此时对 DOM 树的操作开销很低。ng-repeatng-transclude也都是在这个时候对 DOM 树进行操作。

每个指令都可以有自己的模板和编译函数,每个末班返回的都是自己的模板函数。顶部的指令会将其内部包含的所有指令合并在一个模板函数返回。树的内部只能通过模板函数访问所处的分支。

模板函数最终被传到编译后的 DOM 树中每个指令定义规则中指定的链接函数。

compile(对象或函数)

设置了编译函数意味着我们想要在指令被放到 DOM 中之前进行 DOM 操作,这时对 DOM 的操作是安全的。

注意1:compile 函数和 link 函数是互斥的。如果同时实现了它们,compile 函数将会被当做 link 函数,而 link 函数将会被忽略。

注意2:不要在 compile 函数内部进行 DOM 事件监听的注册,这个操作应该放到 link 函数中完成。

link(链接)

它会在模板编译并同作用域进行链接后被调用。他负责设置事件监听器和实时操作 DOM(但要考虑性能问题)。