指令定义时的参数
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 -->
- E 元素方式
- `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 }
9
10 return {compile: func,
11 scope: true,
12 restrict: 'A'};
13 });
14
15 app.directive('b', function(){
16 var func = function(element, attrs, link){
17 return function(scope){
18 console.log(scope);
19 }
20 }
21
22 return {compile: func,
23 restrict: 'A'};
24 });
25
26 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();
9
10 scope.show = function(here){
11 console.log('Inner, ' + here);
12 scope.a({here: 5});
13 }
14 }
15 }
16
17 return {compile: func,
18 scope: {a: '&abc', b: '&ngClick'},
19 restrict: 'A'};
20 });
21
22 app.controller('TestCtrl', function($scope){
23 $scope.here = 123;
24 console.log($scope);
25
26 $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 }
10
11 var controller = function($scope, $element, $attrs, $transclude){
12 console.log('controller');
13 console.log($scope);
14
15 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 }
22
23 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 }
11
12 return {compile: func,
13 name: 'not_a',
14 controller: controller,
15 restrict: 'E'}
16 });
17
18 app.directive('b', function(){
19 var func = function(){
20 return function($scope, $element, $attrs, $controller){
21 console.log($controller);
22 }
23 }
24
25 var controller = function($scope, $element, $attrs, $transclude){
26 console.log('b');
27 }
28
29 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 }
11
12 return {compile: func,
13 restrict: 'E'}
14 });
15
16 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 }
24
25 return {compile: func,
26 restrict: 'E'}
27 });
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论