发表于: 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 没找到,不要抛出异常。
明天计划的事情:
写分页指令。
学习数据结构。
遇到的问题:
暂无
收获:
如上。
评论