1.什么是指令?
指令的职责是修改DOM结构,并且将作用域与DOM连接起来 —— 说明指令既要操作DOM(将作用域内的数据绑定到DOM节点上),又要为DOM绑定事件调用作用域内的对应方法。
AngularJS框架提供的内置指令中不仅包括自定义的HTML元素和属性,同时也包括标准的HTML元素,这些都是AngularJS核心框架默认提供的。而且定义的内置指令的API和自定义指令完全一样,可以阅读源码提高自定义指令的能力。
a: htmlAnchorDirective,
input: inputDirective,
textarea: inputDirective,
form: formDirective,
script: scriptDirective, // script是判断 attr.type == 'text/ng-template'
select: selectDirective,
style: styleDirective,
option: optionDirective
关于指令的书写命名规范,在HTML中使用指令时是使用'-'拼接,在js中定义使用驼峰式命名。
2.理解指令的流程/生命周期
当AngularJS编译一个HTML模板时,它会遍历浏览器提供的DOM树,尝试参照已经注册的指令来匹配每个元素、属性、注释、CSS类 —— EACM。
每当匹配一个指令,就会调用这个指令的编译函数compile,这个编译函数会返回一个链接函数link,AngularJS就会收集所有的link函数。
注意:编译工作是在作用域创建之前执行的,所以在编译函数中没有任何可用的作用域数据。
compile: function(element, attr) {}
link: function ($scope, $element, $attr, ctrl, $transclude) {}
3.指令的编译阶段
编译阶段通常是做一些优化工作,因为对于重复的指令(比如ng-repeat的内部),指令的编译函数只会被调用一次,但是链接函数在每次迭代的时候都是会被调用的。所以如果指令中有一些不依赖于作用域数据的复杂功能,那么这部分功能应该放在编译函数compile中,因为这样这部分函数只会被调用一次。
所以,将代码放在compile函数中还是link函数中,可以看这部分代码跟作用域是否有关系,没有关系就放在compile函数中,有则放在link函数中,这样可以减少被调用的次数。尤其是在ng-repeat这样的重复指令内部。而且如果是对DOM作了非常复杂的操作,那么编译函数的这种机制就会显得非常有价值,尤其是在循环的次数比较多的情况下。
4.指令的链接阶段
一旦所有的指令都被编译完成之后,AngularJS就会创建作用域,然后通过调用每个指令对应的链接函数link将指令和作用域连接起来。
在链接阶段,作用域已经被附加在指令上了,所以链接函数可以讲作用域和DOM绑定起来。
scope.compiledTpl = $compile(template)(scope);
element.append(scope.compiledTpl);
上面第一行相当于:
var linkingFn = $compile(template);
scope.compiledTpl = linkingFn(scope);