多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
### 18.8. 指令定义时的参数 指令定义时的参数如下: - name - priority - terminal - scope - controller - require - restrict - template - templateUrl - replace - transclude - compile - link 现在我们开始一个一个地吃掉它们……,但是并不是按顺序讲的。 _priority_ 这个值设置指令的权重,默认是 `0` 。当一个节点中有多个指令存在时,就按着权限从大到小的顺序依次执行它们的 `compile` 函数。相同权重顺序不定。_terminal_ 是否以当前指令的权重为结束界限。如果这值设置为 `true` ,则节点中权重小于当前指令的其它指令不会被执行。相同权重的会执行。_restrict_ 指令可以以哪些方式被使用,可以同时定义多种方式。 - E 元素方式 `<my-directive></my-directive>` - A 属性方式 `<div my-directive="exp"> </div>` - C 类方式 `<div class="my-directive: exp;"></div>` - M 注释方式 `<!-- directive: my-directive exp -->` _transclude_ 前面已经讲过基本的用法了。可以是 `'element'` 或 `true` 两种值。_compile_ 基本的定义函数。 `function compile(tElement, tAttrs, transclude) { ... }`_link_ 前面介绍过了。大多数时候我们不需要单独定义它。只有 `compile` 未定义时 `link` 才会被尝试。 `function link(scope, iElement, iAttrs, controller) { ... }`_scope_ scope 的形式。 `false` 节点的 scope , `true` 继承创建一个新的 scope , `{}` 不继承创建一个新的隔离 scope 。 `{@attr: '引用节点属性', =attr: '把节点属性值引用成scope属性值', &attr: '把节点属性值包装成函数'}`_controller_ 为指令定义一个 controller , `function controller($scope, $element, $attrs, $transclude) { ... }`_name_ 指令的 controller 的名字,方便其它指令引用。_require_ 要引用的其它指令 conroller 的名字, `?name` 忽略不存在的错误, `^name` 在父级查找。_template_ 模板内容。_templateUrl_ 从指定地址获取模板内容。_replace_ 是否使用模板内容替换掉整个节点, `true` 替换整个节点, `false` 替换节点内容。 <a b></a> var app = angular.module('Demo', [], angular.noop); app.directive('a', function(){ var func = function(element, attrs, link){ console.log('a'); } return {compile: func, priority: 1, restrict: 'EA'}; }); app.directive('b', function(){ var func = function(element, attrs, link){ console.log('b'); } return {compile: func, priority: 2, //terminal: true, restrict: 'A'}; }); 上面几个参数值都是比较简单且容易理想的。 再看 _scope_ 这个参数: <div ng-controller="TestCtrl"> <div a b></div> </div> 1 var app = angular.module('Demo', [], angular.noop); 2 3 app.directive('a', function(){ 4 var func = function(element, attrs, link){ 5 return function(scope){ 6 console.log(scope); 7 } 8 } 910 return {compile: func, 11 scope: true, 12 restrict: 'A'}; 13 }); 1415 app.directive('b', function(){ 16 var func = function(element, attrs, link){ 17 return function(scope){ 18 console.log(scope); 19 } 20 } 2122 return {compile: func, 23 restrict: 'A'}; 24 }); 2526 app.controller('TestCtrl', function($scope){ 27 $scope.a = '123'; 28 console.log($scope); 29 }); 对于 _scope_ : - 默认为 `false` , `link` 函数接受的 `scope` 为节点所在的 `scope` 。 - 为 `true` 时,则 `link` 函数中第一个参数(还有 `controller` 参数中的 `$scope` ), `scope` 是节点所在的 `scope` 的 `child scope` ,并且如果节点中有多个指令,则只要其中一个指令是 `true` 的设置,其它所有指令都会受影响。 这个参数还有其它取值。当其为 `{}` 时,则 `link` 接受一个完全隔离(isolate)的 `scope` ,于 `true` 的区别就是不会继承其它 `scope` 的属性。但是这时,这个 `scope` 的属性却可以有很灵活的定义方式: _@attr_ 引用节点的属性。 <div ng-controller="TestCtrl"> <div a abc="here" xx="{{ a }}" c="ccc"></div> </div> var app = angular.module('Demo', [], angular.noop); app.directive('a', function(){ var func = function(element, attrs, link){ return function(scope){ console.log(scope); } } return {compile: func, scope: {a: '@abc', b: '@xx', c: '@'}, restrict: 'A'}; }); app.controller('TestCtrl', function($scope){ $scope.a = '123'; }); - _@abc_ 引用 div 节点的 abc 属性。 - _@xx_ 引用 div 节点的 xx 属性,而 xx 属性又是一个变量绑定,于是 `scope` 中 `b` 属性值就和 `TestCtrl` 的 `a` 变量绑定在一起了。 - _@_ 没有写 attr name ,则默认取自己的值,这里是取 div 的 c 属性。 _=attr_ 相似,只是它把节点的属性值当成节点 `scope` 的属性名来使用,作用相当于上面例子中的 _@xx_ : <div ng-controller="TestCtrl"> <div a abc="here"></div> </div> var app = angular.module('Demo', [], angular.noop); app.directive('a', function(){ var func = function(element, attrs, link){ return function(scope){ console.log(scope); } } return {compile: func, scope: {a: '=abc'}, restrict: 'A'}; }); app.controller('TestCtrl', function($scope){ $scope.here = '123'; }); _&attr_ 是包装一个函数出来,这个函数以节点所在的 `scope` 为上下文。来看一个很爽的例子: <div ng-controller="TestCtrl"> <div a abc="here = here + 1" ng-click="show(here)">这里</div> <div>{{ here }}</div> </div> 1 var app = angular.module('Demo', [], angular.noop); 2 3 app.directive('a', function(){ 4 var func = function(element, attrs, link){ 5 return function llink(scope){ 6 console.log(scope); 7 scope.a(); 8 scope.b(); 910 scope.show = function(here){ 11 console.log('Inner, ' + here); 12 scope.a({here: 5}); 13 } 14 } 15 } 1617 return {compile: func, 18 scope: {a: '&abc', b: '&ngClick'}, 19 restrict: 'A'}; 20 }); 2122 app.controller('TestCtrl', function($scope){ 23 $scope.here = 123; 24 console.log($scope); 2526 $scope.show = function(here){ 27 console.log(here); 28 } 29 }); scope.a 是 _&abc_ ,即: scope.a = function(){here = here + 1} 只是其中的 `here` 是 `TestCtrl` 的。 scope.b 是 _&ngClick_ ,即: scope.b = function(){show(here)} 这里的 `show()` 和 `here` 都是 `TestCtrl` 的,于是上面的代码最开始会在终端输出一个 `124` 。 当点击“这里”时,这时执行的 `show(here)` 就是 `llink` 中定义的那个函数了,与 `TestCtrl` 无关。但是,其间的 `scope.a({here:5})` ,因为 `a` 执行时是 `TestCtrl` 的上下文,于是向 `a` 传递的一个对象,里面的所有属性 `TestCtrl` 就全收下了,接着执行 `here=here+1` ,于是我们会在屏幕上看到 `6` 。 这里是一个上下文交错的环境,通过 _&_ 这种机制,让指令的 `scope` 与节点的 `scope` 发生了互动。真是鬼斧神工的设计。而实现它,只用了几行代码: case '&': { parentGet = $parse(attrs[attrName]); scope[scopeName] = function(locals) { return parentGet(parentScope, locals); } break; } 再看 _controller_ 这个参数。这个参数的作用是提供一个 controller 的构造函数,它会在 `compile` 函数之后, `link` 函数之前被执行。 <a>haha</a> 1 var app = angular.module('Demo', [], angular.noop); 2 3 app.directive('a', function(){ 4 var func = function(){ 5 console.log('compile'); 6 return function(){ 7 console.log('link'); 8 } 9 } 1011 var controller = function($scope, $element, $attrs, $transclude){ 12 console.log('controller'); 13 console.log($scope); 1415 var node = $transclude(function(clone_element, scope){ 16 console.log(clone_element); 17 console.log('--'); 18 console.log(scope); 19 }); 20 console.log(node); 21 } 2223 return {compile: func, 24 controller: controller, 25 transclude: true, 26 restrict: 'E'} 27 }); `controller` 的最后一个参数, `$transclude` ,是一个只接受 `cloneAttachFn` 作为参数的一个函数。 按官方的说法,这个机制的设计目的是为了让各个指令之间可以互相通信。参考普通节点的处理方式,这里也是处理指令 `scope` 的合适位置。 <a b>kk</a> 1 var app = angular.module('Demo', [], angular.noop); 2 3 app.directive('a', function(){ 4 var func = function(){ 5 } 6 7 var controller = function($scope, $element, $attrs, $transclude){ 8 console.log('a'); 9 this.a = 'xx'; 10 } 1112 return {compile: func, 13 name: 'not_a', 14 controller: controller, 15 restrict: 'E'} 16 }); 1718 app.directive('b', function(){ 19 var func = function(){ 20 return function($scope, $element, $attrs, $controller){ 21 console.log($controller); 22 } 23 } 2425 var controller = function($scope, $element, $attrs, $transclude){ 26 console.log('b'); 27 } 2829 return {compile: func, 30 controller: controller, 31 require: 'not_a', 32 restrict: 'EA'} 33 }); _name_ 参数在这里可以用以为 `controller` 重起一个名字,以方便在 _require_ 参数中引用。 _require_ 参数可以带两种前缀(可以同时使用): - _?_ ,如果指定的 controller 不存在,则忽略错误。即: require: '?not_b' 如果名为 `not_b` 的 controller 不存在时,不会直接抛出错误, `link` 函数中对应的 `$controller` 为 `undefined` 。 - _^_ ,同时在父级节点中寻找指定的 controller ,把上面的例子小改一下: <a><b>kk</b></a> 把 `a` 的 _require_ 改成(否则就找不到 `not_a` 这个 controller ): require: '?^not_a' 还剩下几个模板参数: _template_ 模板内容,这个内容会根据 _replace_ 参数的设置替换节点或只替换节点内容。_templateUrl_ 模板内容,获取方式是异步请求。_replace_ 设置如何处理模板内容。为 `true` 时为替换掉指令节点,否则只替换到节点内容。 <div ng-controller="TestCtrl"> <h1 a>原始内容</h1> </div> var app = angular.module('Demo', [], angular.noop); app.directive('a', function(){ var func = function(){ } return {compile: func, template: '<p>标题 {{ name }} <button ng-click="name=\'hahaha\'">修改</button></p>', //replace: true, //controller: function($scope){$scope.name = 'xxx'}, //scope: {}, scope: true , controller: function($scope){console.log($scope)}, restrict: 'A'} }); app.controller('TestCtrl', function($scope){ $scope.name = '123'; console.log($scope); }); _template_ 中可以包括变量引用的表达式,其 `scope` 遵寻 _scope_ 参数的作用(可能受继承关系影响)。 _templateUrl_ 是异步请求模板内容,并且是获取到内容之后才开始执行指令的 `compile` 函数。 最后说一个 _compile_ 这个参数。它除了可以返回一个函数用为 `link` 函数之外,还可以返回一个对象,这个对象能包括两个成员,一个 _pre_ ,一个 _post_ 。实际上, `link` 函数是由两部分组成,所谓的 _preLink_ 和 _postLink_ 。区别在于执行顺序,特别是在指令层级嵌套的结构之下, _postLink_ 是在所有的子级指令 `link` 完成之后才最后执行的。 _compile_ 如果只返回一个函数,则这个函数被作为 _postLink_ 使用: <a><b></b></a> 1 var app = angular.module('Demo', [], angular.noop); 2 3 app.directive('a', function(){ 4 var func = function(){ 5 console.log('a compile'); 6 return { 7 pre: function(){console.log('a link pre')}, 8 post: function(){console.log('a link post')}, 9 } 10 } 1112 return {compile: func, 13 restrict: 'E'} 14 }); 1516 app.directive('b', function(){ 17 var func = function(){ 18 console.log('b compile'); 19 return { 20 pre: function(){console.log('b link pre')}, 21 post: function(){console.log('b link post')}, 22 } 23 } 2425 return {compile: func, 26 restrict: 'E'} 27 });