AngularJS开发指南4:指令的详解

指令是我们用来扩展浏览器能力的技术之一。在DOM编译期间,和HTML元素关联着的指令会被检测到,并且被执行。这使得指令可以为DOM指定行为,或者改变它。

AngularJS有一套完整的、可扩展的、用来帮助web应用开发的指令集,它使得HTML可以转变成“特定领域语言(DSL)”。

指令可以做为HTML中的元素名,属性名,类名,或者注释。下面是一些等效调用myDir指令的例子:

<span my-dir="exp"></span> <span></span> <my-dir></my-dir> <!-- directive: my-dir exp -->

angular在编译期间,编译器会用$interpolate服务去检查文本中是否嵌入了表达式。这个表达式会被当成一个监视器一样注册,并且作为$digest循环中的一部分,它会自动更新。

HTML的编译分为三个阶段:

首先浏览器会用它的标准API将HTML解析成DOM。 你需要认清这一点,因为我们的模板必须是可被解析的HTML。这是AngularJS和那些“以字符串为基础而非以DOM元素为基础的”模板系统的区别之处。

DOM的编译是由$compile方法来执行的。 这个方法会遍历DOM并找到匹配的指令。一旦找到一个,它就会被加入一个指令列表中,这个列表是用来记录所有和当前DOM相关的指令的。 一旦所有的指令都被确定了,会按照优先级被排序,并且他们的compile方法会被调用。 指令的$compile()函数能修改DOM结构,并且要负责生成一个link函数(后面会提到)。$compile方法最后返回一个合并起来的链接函数,这时链接函数是每一个指令的compile函数返回的链接函数的集合。

通过调用上一步所说的链接函数来将模板与作用域链接起来。这会轮流调用每一个指令的链接函数,让每一个指令都能对DOM注册监听事件,和建立对作用域的的监听。这样最后就形成了作用域的DOM的动态绑定。任何一个作用域的改变都会在DOM上体现出来。

 

var html = '<div ng-bind='exp'></div>'; // Step 1: parse HTML into DOM element var template = angular.element(html); // Step 2: compile the template var linkFn = $compile(template); // Step 3: link the compiled template with the scope. linkFn(scope);

 

你可能会疑惑为什么编译过程和链接过程要分离。要明白其中的原因,你可以先看下面这个带有“重复指令”的例子:

Hello {{user}}, you have these actions: <ul> <li ng-repeat="action in user.actions"> {{action.description}} </li> </ul>

当上面的例子被编译后,编译器会遍历所有节点来寻找指令。例如{{user}}是一个替换式指令,ngRepeat是另一个指令。但是ngRepeat有一个难题。他需要为user.actions中的每一个action 构造一个li。这意味着它先要保存一个“干净”的li元素来用作克隆,然后等新的action插入进来时,克隆这个干净的li元素,把克隆出来的li元素插入到ul中。但是仅仅克隆li的话工作还没完。他还需要编译这个li才能把其中的{{action.descriptions}}的替换式替换成相应作用域下的值。我们可以用一个简单的方法来克隆和插入li元素,然后编译它。但是要编译每一个li的话,速度会很慢, 因为编译的工程需要我们遍历DOM树。如果我们在一个需要循环100次循环体内执行编译的话,性能问题就会马上凸现出来。

而我们的解决方案就是将编译工程分为两个阶段。编译阶段将指令识别出来并按优先级排序,链接阶段将作用域中的实例和li进行链接。

ngRepeat 会阻止li子元素{{action.description}}的编译,取而代之的是 ngRepeat指令会单独对li进行编译,编译时,会生成多个li元素组成的模板。这个编译结束后会生成一个链接函数,这个函数在执行时,会对整个模板进行编译,然后为每一个li元素创建一个新的作用域,并把它和对应的作用域链接上。这里,我们只需要编译一次(对模板进行一次统一的编译就行了),只是在链接的时候,需要链接多次,而链接操作并不消耗性能。

如何写一个指令

 

var myModule = angular.module(...); myModule.directive('directiveName', function factory(injectables) { var directiveDefinitionObject = { priority: 0, template: '<div></div>', templateUrl: 'directive.html', replace: false, transclude: false, restrict: 'A', scope: false, compile: function compile(tElement, tAttrs, transclude) { return { pre: function preLink(scope, iElement, iAttrs, controller) { ... }, post: function postLink(scope, iElement, iAttrs, controller) { ... } } }, link: function postLink(scope, iElement, iAttrs) { ... } }; return directiveDefinitionObject; });

 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/bdbd967da56bc9cdf37fd9ee92e05d94.html