——本文转自他处,稍作修改,完全为了方便自己理解,如有侵犯,请告知。
指令(Directives)是所有AngularJS应用最重要的部分。尽管AngularJS已经提供了非常丰富的指令,但还是经常需要创建应用特定的指令。
一个Angular指令可以有以下的四种表现形式:
1. 一个新的HTML元素(<data-picker></data-picker>) (A)
2. 元素的属性(<input type=”text” data-picker/>) (E)
3. CSS class(<input type=”text” class=”data-picker”/>) (C)
4. 注释(<!–directive:data-picker –>) (M)
当然,我们可以控制我们的指令在HTML中的表现形式。下面我们来看一下AngularJS中的一个典型的指令的写法。指令注册的方式与 controller 一样,但是它返回的是一个拥有指令配置属性的简单对象(指令定义对象) 。
首先,创建一个指令:
var app = angular.module('myapp', []);
app.directive('helloWorld', function() {
return {
restrict: 'AE',
replace: 'true',
template: '<h1>Hello World!!</h1>'
};
});
通过指令定义的元素属性(A)和标签属性(E)来使用该指令:
元素属性使用:
<hello-world/>或<hello:world/>
标签属性使用:
<div hello-world></div>或<div hello:world/>
通过上面的例子,我们看到restrict设置为AE,其意如上所说,共有四种定义,分别为A,E,C,M;
还有replace设置为true代表着生成的HTML内容是会替换掉定义此指令的HTML元素,即
<hello-world/>或<hello:world/>、<div hello-world></div>或<div hello:world/>
如果为false,则默认值,生成的模板会被插入到元素中去;
还有templat:这个属性规定了指令被Angular编译和链接(link)后生成的HTML标记。这个属性值不一定要是简单的字符串。template 可以非常复杂,而且经常包含其他的指令,以及表达式({{ }})等。更多的情况下你可能会见到 templateUrl, 而不是 template。所以,理想情况下,你应该将模板放到一个特定的HTML文件中,然后将 templateUrl 属性指向它。
link和scope
<body ng-controller="myController">
<input type="text" ng-model="color" />
<hello-world/>
</body>
app.directive('helloWorld', function() {
return {
restrict: 'AE',
replace: true,
template: '<p style="background-color:{{color}}">Hello World',
link: function(scope, elem, attrs) {
elem.bind('click', function() {
elem.css('background-color', 'white');
scope.$apply(function() {
scope.color = "white";
});
});
elem.bind('mouseover', function() {
elem.css('cursor', 'pointer');
});
}
};
});
以上link函数有三个参数:
compile函数
compile 函数在 link 函数被执行之前用来做一些DOM改造。它接收下面的参数:2、 attrs – 元素上赋予的参数的标准化列表
app.directive('myDirective', function() {
return {
compile: function(tElem,attrs) {
return function(scope,elem,attrs) {
};
}
};
});
多数情况下我们只用到link函数,这是因为大部分的指令只需要考虑注册事件监听、监视模型、以及更新DOM等,这些都可以在 link 函数中完成。
改变指令的scope
默认情况下,指令获取它父节点的controller的scope。但这并不适用于所有情况。如果将父controller的scope暴露给指令,那么他们可以随意地修改 scope 的属性。在某些情况下,你的指令希望能够添加一些仅限内部使用的属性和方法。如果我们在父的scope中添加,会污染父scope。 其实我们还有两种选择:app.directive('helloWorld', function() {
return {
scope: true,
restrict: 'AE',
replace: 'true',
template: '<h3>Hello World!!</h3>'
};
});
app.directive('helloWorld', function() {
return {
scope: {},
restrict: 'AE',
replace: 'true',
template: '<h3>Hello World!!</h3>'
};
});
通过隔离scope,我们可以创建重用的指令非常有好处, 我们能够保证我们的指令是自包含的,可以被很容易的插入到HTML应用中。 它内部不能访问父的scope,所保证了父scope不被污染。
隔离scope和父scope之间的数据绑定
隔离指令的scope会带来很多的便利,尤其是在你要操作多个scope模型的时候。但有时为了使代码能够正确工作,你也需要从指令内部访问父scope的属性。选择一:使用 @ 实现单向文本绑定
在下面的指令定义中,我们指定了隔离scope中的属性 color 绑定到指令所在HTML元素上的参数 colorAttr。在HTML标记中,你可以看到 {{color}}表达式被指定给了 color-attr 参数。当表达式的值发生改变时,color-attr 参数也跟着改变。隔离scope中的 color 属性的值也相应地被改变。app.directive('helloWorld', function() {
return {
scope: {
color: '@colorAttr'
},
....
};
});
<body ng-controller="MainCtrl">
<input type="text" ng-model="color" />
<hello-world color-attr="{{color}}"/>
</body>
注意点:
当隔离scope属性和指令元素参数的名字一样时,我们可以更简单的方式设置scope绑定:
app.directive('helloWorld', function() {
return {
scope: {
color: '@'
},
....
};
});
<hello-world color="{{color}}"/>
选择二:使用 = 实现双向绑定
我们把指令的定义改变成下面的样子:app.directive('helloWorld', function() {
return {
scope: {
color: '='
},
....
};
});
<body ng-controller="MainCtrl">
<input type="text" ng-model="color" />
<hello-world color="color"/>
</body>
与 @ 不同,这种方式让你能够给属性指定一个真实的scope数据模型,而不是简单的字符串。这样你就可以传递简单的字符串、数组、甚至复杂的对象给隔离scope。同时,还支持双向的绑定。每当父scope属性变化时,相对应的隔离scope中的属性也跟着改变,反之亦然。和之前的一样,你也可以监视这个scope属性的变化。
选择三:使用 & 在父scope中执行函数
有时候从隔离scope中调用父scope中定义的函数是非常有必要的。为了能够访问外部scope中定义的函数,我们使用 &。比如我们想要从指令内部调用 sayHello() 方法。app.directive('sayHello', function() {
return {
scope: {
sayHelloIsolated: '&'
},
....
};
});
<body ng-controller="MainCtrl">
<input type="text" ng-model="color" />
<say-hello sayHelloIsolated="sayHello()"/>
</body>