这篇文章,我们将通过一个实例来了解 Angular 的 directives (指令)是如何处理的。Angular 是如何在 HTML 中找到这些 directive 的。以及如何编写自定义的指令。
这是原文提供的代码:http://www.angularjshub.com/examples/customdirectives/compilelinkfunctions/#top
更加友好的排版:http://blog.wangtuyao.com/post/2014/7/2/compile-and-link-function-in-angular
当 Angular 从 HTML 中解析 directive 的时候,我们每个 directive 的解析可以大致分为 3 步。
initialization
允许 directive 做一些初始化的工作。compilation:这个阶段 Angular 遍历 DOM ,并且收集所有的 directive 。所有 directive 都可以在这个阶段操作 DOM(在这个阶段,同一个 directive 在不同的 DOM 节点如果中出现了多次,compilation 将会执行多次)这个阶段 scope 是还没有被附加上去,所以是无法访问到 scope 的。
linking:这个阶段的 DOM 节点,Angular 会把所有 directive 的事件监听器(event listeners)注册到 DOM 中,建立对 scope 的监听。并且把一个 scope 附加到 directive 中。这整个阶段是在compilation之后进行的。如果想要访问 scope 就可以在这个阶段进行。
我们可以通过 Angular 中提供的directive创建自定义的指令。
directive(name, directiveFactory);
方法提供了两个参数,第一个为 directive 的名字,第二个是一个工厂方法。
在 HTML 中指定来引用一个指令有多种方法,查看更多内容。directive 的命名说有几种约定的规则:
例如:directive 的名称为myCustomDir
所有 HTML 中引用为my-custom-dir
;
上文讲了 initialization, compilation 和 linking 阶段,现在来看一下 directive 是如何执行的。这是一个最为复杂的例子,这个例子包含了 directive 处理的所有阶段。
myModule.directive("myCustomDir", function () { // Initialization // ... // Definition object return { // Compile function compile: function (element, attrs) { // ... return { // PRe-link function pre: function (scope, element, attrs) { // ... }, // Post-link function post: function (scope, element, attrs) { // ... } }; } }; });
第一个参数表示 directive 的名字,第二个参数表示 directive 的工厂方法,返回一个对象。这个对象可以包含多个属性,查看更多。这里我们只关注compile
属性。compile
对应了一个compile function,这个方法返回一个包含pre
和post
属性的对象。为了能更好的理解情况下图:
假如我们定义了如下的自定义的 directive dir1,dir2,dir3 和 dir4 ,Angular 又是如何处理的呢
<... dir1 ...> <... dir2 dir3 ...> <... dir4 dir1 ...> </...> </...></...>
initialization 和 compilation 阶段将会在第一次遍历 DOM 的时候发生。这里是处理过程:
dir1
将会首先被发现。所以dir1
的initialization
将会首先执行,紧接着的是dir1
的compilation
。dir2
,dir3
;dir2
和dir3
是 DOM 第一次遍历到,所以initialization
部分和compilation
部分会依次调用;dir2
和dir3
的子 node,这里包含了dir4
和dir1
。因为dir1
在第一步的时候已经initialization
过,所以不会再次执行,但是dir4
还是会调用initialization
因为它是 DOM 第一次遍历到。所有的 directive 都会在initialization
后调用compilation
。如果 html 中还有其他的 DOM 树,处理过程也是类似的,以同样的方式从上到下遍历 DOM 树,如果有 DOM 节点存在着子节点,每个字节点都将会被依次遍历后再进入下一个节点。这个过程结束之后,initialization
和compilation
的处理也结束了。directive 将会被替换,最终版本的 DOM 树将会呈现出来。
接下来的处理过程是linking。这个过程有可以细分为pre-linking和post-linking。由于 Angular 使用depth-first方式遍历 DOM 树。所以 angular 首先访问到的是pre-linking,当所有pre-linking执行完毕后,DOM 遍历进入到一个“回溯”(backtracking )阶段的时候所有的post-linking才执行。在pre-linking函数做DOM 的转换时不安全的(pre-linking的执行是在节点的子节点还未执行link,意思是:在某一个节点执行pre-linking的时候,这个节点的子节点还未进行 link),在post-linking阶段才是安全的。
上文,我们已经知道了一种方式在一个模块中创建一个指令,并且这是一种最复杂的方式,因为我们既需要访问 compile ,pre-link,和 post-link,但是通常情况下我们不需要全部,我们可以根据需求选择不同的函数。我们开看一下几种方式(代码请看上面的链接):
不定义对象
我们可以简单的 Post-link 后,不定义对象返回。这是在例 1. 所示。
myModule.directive("myCustomDir", function (){ // Initialization // ... // Post-link function return function (scope, element, attrs) { // ... };});
定义一个对象和只定义一个 post-link 函数
定义对象后返回 post-link 函数,如例 2.所示:
myModule.directive("myCustomDir", function (){ // Initialization // ... // Definition object return { // Post-link function link: function (scope, element, attrs) { // ... } };});
定义一个对象和定义 post-klink 和 pre-link
返回一个对象,这个对象有一个link属性,这个 link 属性又包含一个pre
和post
属性的对象,分别对应 pre-link 函数和 post-link 函数。如实例 3.所示:
myModule.directive("myCustomDir", function (){ // Initialization // ... // Definition object return { link: { // Pre-link function pre: function (scope, element, attrs) { // ... }, // Post-link function post: function (scope, element, attrs) { // ... } } };});
定义一个对象和只定义 compile 函数
返回一个对象,包含 compile 属性,对应 compile 函数,如例 4. 所示:
myModule.directive("myCustomDir", function (){ // Initialization // ... // Definition object return { // Compile function compile: function (element, attrs) { // ... } };});
定义一个对象和定义 compile 和 post-link 函数
定义一个对象和定义 compile 和 post-link 函数,如例 5.所示:
myModule.directive("myCustomDir", function (){ // Initialization // ... // Definition object return { // Compile function compile: function (element, attrs) { // ... // Post-link function return function (scope, element, attrs) { // ... }; } };});
定义一个对象和 compile,pre-link 和 post-link 函数
最后一种方式,如例 6.所示
myModule.directive("myCustomDir", function (){ // Initialization // ... // Definition object return { // Compile function compile: function (element, attrs) { // ... return { // Pre-link function pre: function (scope, element, attrs) { // ... }, // Post-link function post: function (scope, element, attrs) { // ... } }; } };});
我们已经了解了在自定义指令中定义 compile 和 link 函数。现在来看一下 compile 和 link 的参数。
Angular 使用了一种内置的、轻量级的 jQuery,称为jqLite来操作和查询 DOM。但如果页面中同时有 jQuery 存在,那么 Angular 会用 jQuery 替换掉内置的 jqLite。
compile 函数的签名如下:
function (element, attrs)
link 函数的签名如下:
function (scope, element, attrs)
新闻热点
疑难解答