发表于: 2017-07-01 23:30:41

1 821


今天完成的任务:

继续学习angular指令


A.指令的解析流程详解:

       1. ng 框架会在页面载入完毕的时候,根据 ng-app 划定的作用域来调用 $compile 服务进行编译,清点作用域内的 DOM 元素,然后根据这些指令的优先级 (priority) 排列一下,根据指令中的配置参数 (template,place,transclude 等) 转换 DOM,让指令“初具人形”。

     2.然后就开始按顺序执行各指令的 compile 函数,注意此处的 compile 不是 $compile,此处执行的 compile 函数是我们指令中配置的,compile 函数中可以访问到 DOM 节点并进行操作,其主要职责就是进行 DOM 转换,每个 compile 函数执行完后都会返回一个 link 函数,这些 link 函数会被$compile汇合一下组合成一个合体后的 link 函数,为了好理解,我们可以把它想象成葫芦小金刚。

  3.接下来进入 link 阶段,合体后的 link 函数被执行。所谓的链接,就是把 view 和 scope 链接起来。这就是我们熟悉的数据绑定,通过在 DOM 上注册监听器来动态修改 scope 中的数据,或者是使用 $watchs 监听 scope 中的变量来修改 DOM,从而建立双向绑定。由此也可以断定,葫芦小金刚可以访问到 scope 和 DOM 节点。

 4.我们在定义指令中还配置着一个 link 参数,compile 函数执行后返回此 link 函数,若没有配置 compile 函数? $compile 就把这里的 link 函数拿来执行。配置的 link 函数也可以访问到 scope 以及 DOM 节点。compile 函数通常是不会被配置的,因为我们定义一个指令的时候,大部分情况不会通过编程的方式进行 DOM 操作,而更多的是进行监听器的注册、数据的绑定。


B.compile 和 link 之间到底有什么区别:

a. 首先是性能举个例子:

<ul>
<li ng-repeat="a in array">
<input ng-modle=”a.m” />
</li>
</ul>

         我们的观察目标是 ng-repeat 指令。假设一个前提是不存在 link。$compile 在编译这段代码时,会查找到 ng-repeat,然后执行它的 compile 函数,compile 函数根据 array 的长度复制出 n 个 <li> 标签。而复制出的 < li > 节点中还有 < input > 节点并且使用了 ng-modle 指令,所以 compile 还要扫描它并匹配指令,然后绑定监听器。每次循环都做如此多的工作。而更加糟糕的一点是,我们会在程序中向 array 中添加元素,此时页面上会实时更新 DOM,每次有新元素进来,compile 函数都把上面的步骤再走一遍,这样性能必然不行。

         现在扔掉那个假设,在编译的时候 compile 就只管生成 DOM 的事,碰到需要绑定监听器的地方先存着,有几个存几个,最后把它们汇总成一个 link 函数,然后一并执行。这样就轻松多了,compile 只需要执行一次,性能自然提升。


b.另外一个区别是能力:

         我们需要看一下 compile 函数和 link 函数的定义:

function compile(tElement, tAttrs, transclude) { ... }
function link(scope, iElement, iAttrs, controller) { ... }   

        compile 可以拿到 transclude,允许你自己编程管理乾坤大挪移的行为。 link 中可以拿到 scope 和 controller,可以与 scope 进行数据绑定,与其他指令进行通信。两者虽然都可以拿到 element,但是是有区别的,compile 拿到的是编译前的,是从 template 里拿过来的,而 link 拿到的是编译后的,已经与作用域建立了关联,这也正是 link 中可以进行数据绑定的原因。


总结:如果指令只进行 DOM 的修改,不进行数据绑定,那么配置在 compile 函数中,如果指令要进行数据绑定,那么配置在 link 函数中。


C.使用 scope 为指令划分作用域

取值

说明

false

默认值。使用父作用域作为自己的作用域

true

新建一个作用域,该作用域继承父作用域

javascript 对象

与父作用域隔离,并指定可以从父作用域访问的变量

最有用的还是取值为第三种,一个对象,可以用键值来显式的指明要从父作用域中使用属性的方式:

例子如下:

app.controller('testC',function($scope){
$scope.content = '今天天气真好!';
});
app.directive('sayHello',function(){
return {
restrict : 'E',
template : '<div>hello,<b ng-transclude></b>,{­{cont}­}</div>',
replace : true,
transclude : true,
scope : {
cont : '=speak'
       }
};
});

对于符号的说明:

符号

说明

举例

@

传递一个字符串作为属性的值.

str : ‘@string’

=

使用父作用域中的一个属性,绑定数据到指令的属性中.

name : ‘=username’

&

使用父作用域中的一个函数, 可以在指令中调用

getName : ‘&getUserName’

上面的例子的执行流程:

  ① 指令被编译的时候会扫描到 template 中的 {{cont} },发现是一个表达式;

  ② 查找 scope 中的规则:通过 speak 与父作用域绑定,方式是传递父作用域中的属性;

  ③ speak 与父作用域中的 content 属性绑定,找到它的值 “今天天气真好!”

  ④ 将 content 的值显示在模板中


D.使用 controller 和 require 进行指令间通信

   a.controller 参数用于定义指令对外提供的接口。

 b.require 参数便是用来指明需要依赖的其他指令,它的值是一个字符串,我们可以在名字前面加个小小的前缀:

^,表示从父节点上寻找。

如果不加,$compile 服务只会从节点本身寻找。

?,告诉 $compile 服务,如果所需的 controller 没找到,不要抛出异常。



明天计划的事情:

写分页指令。

学习数据结构。


遇到的问题:

暂无


收获:

如上。


返回列表 返回列表
评论

    分享到