大部分情况下你不需要控制这么多细节,要简化上面的代码,我们首先需要依赖基本选项的默认值。如果使用默认值的话,上面的代码可以简化成:
var myModule = angular.module(...); myModule.directive('directiveName', function factory(injectables) { var directiveDefinitionObject = { compile: function compile(tElement, tAttrs) { return function postLink(scope, iElement, iAttrs) { ... } } }; return directiveDefinitionObject; });
由于大部分的指令只关心实例,并不需要将模板进行变形,所以我们还可以简化成:
var myModule = angular.module(...); myModule.directive('directiveName', function factory(injectables) { return function postLink(scope, iElement, iAttrs) { ... } });
上面代码中的factory函数,我们叫工厂函数,它是用来创建指令的。它只会被调用一次:就是当编译器第一次匹配到相应指令的时候,你可以在其中进行任何初始化的工作。调用它时使用的是 $injector.invoke , 所以它遵循所有注入器的规则。
指令定义对象,也就是上面代码中的directiveDefinitionObject对象,给编译器提供了生成指令需要的细节。这个对象的属性有:
名称name - 当前作用域的名称。
优先级priority - 当一个DOM上有多个指令时,就会需要指定指令执行的顺序。 这个优先级就是用来在执行指令的compile函数前,先排序的。高优先级的先执行。
terminal - 如果被设置为true,那么该指令就会在同一个DOM的指令集中最后被执行。
作用域scope- 如果被定义成:
true - 那么就会为当前指令创建一个新的作用域。如果有多个在同一个DOM上的指令要求创建新作用域,那么只有一个新的会被创建。 这一创建新作用域的规则不适用于模板的根节点,因为模板的根节点总是会得到一个新的作用域。
{},对象哈希 - 那么一个新的“孤立的”作用域就会被创建。这个“孤立的”作用域区别于一般作用域的地方在于,它不会以原型继承的方式直接继承自父作用域。这对于创建可重用的组件是非常有用的,因为可重用的组件一般不应该读或写父作用域的数据。 这个“孤立的”作用域使用一个对象哈希来表示,这个哈希定义了一系列本地作用域属性,这些属性的值可以有以下几种方式。
@ 或 @attr - 将本地作用域成员和DOM属性绑定。绑定结果总是一个字符串,因为DOM的属性就是字符串。那@和@attr的区别是什么呢?举个例子:@的方式:<widget flater="hello {{name}}"> 和作用域对象: { flater:'@' }。当DOM属性flater的name值改变的时候, 作用域中的flater也会改变,因为本地作用域成员flater绑定了此指令widget的DOM属性flater,同时DOM属性flater的name的值是从父作用域中读来的,也就是说���作用域有name属性。@attr的方式:<widget my-attr="hello {{name}}"> 和作用域对象: { localName:'@myAttr' }。当name值改变的时候, 作用域中的LocalName也会改变。它的特点是:父作用域传递一个属性给子作用域。
= 或 =expression - 在本地作用域属性和父作用域属性间建立一个双向的绑定。 =的方式: <widget flater="parentModel"> 和作用域对象: { flater:'=' }, 本地属性flater会反映父作用域中parentModel的值,flater和parentModel的任一方改变都会影响对方,原理就是:flater是子作用域的属性,parentModel是父作用域的属性,它们进行了双向绑定,一方改变,另一方也会改变,它们是通过DOM属性flater联系在一起的。=expression的方式: <widget my-attr="parentModel"> 和作用域对象: { localModel:'=myAttr' }, 本地属性localModel会反映父作用域中parentModel的值。它的特点:父作用域下的属性跟子作用域下的属性进行双向绑定。
& 或 &attr - 比如:<widget flater="sayHello(name)">和作用域对象:{flater:'&'},这时本地属性flater绑定了父作用域下的sayHello方法。这时,你在子作用域下调用flater方法其实就是调用父作用域下的sayHello方法。如果需要传参的话,是通过flater({name:"chaojidan"})。它的特点:父作用域下传递一个函数给子作用域。