var app = angular.module("directiveModule", []);
app.directive("helloWorld", function() {
return {
restrict: "ACE",
replace: true,
template: "<h1> My First Custom Directive</h1>"
}
});
directive()方法接收两个参数:第一个参数为指令名称,采用驼峰式命名法;第二个参数为指令定义方法,需要返回一个对象(成为指令定义对象DDO),用于描述指令的特征及指令对应的处理逻辑。我们可以向指令定义方法中注入一些依赖,例如$http、$rootScope等。
当我们的指令名称采用驼峰式命名法后,在指令使用时可以使用“-”或者“:”将多个单词隔开。
1. 指令定义对象(DDO)
1.1 restrict属性
指令使用形式有4种:
· E - Element元素:<hello-world></hello-world>
· A - Attribute属性:<div hello-world></div>
· C - Class样式:<div class="hello-word"></div>
· M - Comment注释: <!-- hello-world -->
1.2 replace属性
该属性用于指定是否使用template属性定义的HTML模板内容替换指令所在的HTML元素。
1.3 template属性
该属性指定AngularJS指令被替换成的HTML模板。template的HTML内容也可以使用指令和AngularJS表达式,AngularJS会先解析指令模板中的其他指定和表达式,然后把最终的结果输出到指令使用处。
2. 指令定义对象详解
2.1 link方法
像需要访问指令属性的情况就可以使用指令定义对象的link()方法。
html:
<say-hello name = "Smith"></say-hello>
js:
var app = angular.module("directiveModule",[]);
app.directive("sayHello", function(){
return {
restrict: "ACE",
replace: true,
template: "<h1>Hello , {{name}}</h1>"
link: function(scope, elem, attrs){
scope.name = attrs.name;
}
}
});
三个参数:
· scope参数:表示指令作用域,默认情况下和父级作用域相同。当指令在ng-controller所在的元素开始标签和结束标签之间使用时,该指令会使用控制器对象的作用域,因此可以在link()方法中增加模型数据。在上面的代码中,我们在作用域对象中增加了一个name属性。
· elem参数:表示应用当前指令的HTML元素。并且是经过JQLite包装后的元素。JQLite是jQuery的一个子集,用于方便基本的DOM操作。如果想使用jQuery,只需通过<script>标签将jQuery库文件引入当前页面中,elem将会成为jQuery包装后的元素。
attrs参数:表示一个对象,包含指令的所有属性及属性值。
另外,link()方法的作用并不局限于此,还可以使用在以下场景:
· 需要获取或修改自定义指令属性时
· 当指令需要监视AngularJS作用域模型数据变化时
· 当指令需要响应HTML模板中元素单击、鼠标移动等事件时。
<!DOCTYPE html>
<html ng-app="directiveModule">
<head> <meta charset="utf-8">
<title>ch08_07</title>
<script type="text/javascript" src="../../angular-1.5.5/angular.js"></script>
</head>
<body>
<div>
<hello-world></hello-world>
</div>
<script type="text/javascript">
var app = angular.module("directiveModule", []);
app.directive("helloWorld", function(){
return {
restrict: "ACE",
replace: true,
template: "<div><input type='text' ng-model='message' /><h1>Hello, world! {{message}}</h1><button ng-click='clearMessage()'>清除信息</button></div>",
link: function(scope, elem, attrs) {
scope.$watch("message", function(value) { console.log("newValue:" + value); });
scope.clearMessage = function() { scope.message = ""; }
}
}
});
</script>
</body>
</html>
2.2 compile方法
AngularJS处理指令的过程。浏览器开始渲染HTML页面时,首先加载HTML元素、创建文档对象模型(DOM),加载完成后会触发onload事件。我们通过<script>标签将AngularJS引入HTML页面中,AngularJS就会监听onload事件,然后从DOM元素中查找ng-app指令,如果找到就启动AngularJS框架,接着从ng-app指令所在的HTML标签开始使用$compile服务遍历DOM元素。我们使用的directive()方法注册的指令都会保存在一个容器中,AngularJS会从这些DOM元素中识别哪些属于指令元素,AngularJS框架会根据指令定义对象决定如何处理这些指令。一旦所有的指令都被识别,就会执行指令定义对象的compile()方法。
所有指令的compile()方法只会在AngularJS框架启动时调用一次,该方法定义如下:
compile: function(tElem, tAttrs) {
return {
link: function(scope, iElem, iAttrs){}
}
}
compile()方法可接收两个参数,含义如下:
· tElem:指令所在的元素
· tAttrs:指令元素的所有属性列表
compile()方法和link()方法有冲突,如果指定了指令定义对象的compile()方法就不能再为指令定义对象增加link()方法,但是link()方法可以由compile()方法作为返回值返回。
compile()方法只在AngularJS应用启动时执行一次,但是link()方法会针对每个被复制的实例执行,如果分开处理,就会在性能上有一定的提高。
compile()方法的主要作用是在link()方法执行之前对DOM元素进行修改,下面就用一个案例说明compile()方法的使用场合:
2.3 scope属性与指令作用域
默认情况下,指令直接使用父作用域。摆脱父作用域的两种方案:
· 使用子作用域从父作用域原型继承
· 使用孤立作用域,即创建一个新的作用域对象,和父作用域没有任何关系
var app = angular.module("app",[]);
app.directive("helloWorld", function(){
return {
scope: true,
restrict: "AE",
……
}
})
通过设置scope属性为true,将会为指令创建一个新的作用域,该作用域对象会从父作用域原型继承。
var app = angular.module("app",[]);
app.directive("helloWorld", function(){
return {
scope: {},
restrict: "AE",
……
}
})
通过将scope的属性设置为{},即可为指令创建一个孤立的作用域。
2.4 孤立作用域与父作用域模型数据绑定
· 使用@符号建立基于属性的绑定
或者
<say-hello name-attr="{{name}}"></say-hello>
scope: { name: "@nameAttr"}
· 使用=符号建立双向绑定
<say-hello name-attr="name"></say-hello>
scope: { name: "=nameAttr"}
· 使用&符号调用父作用域中的方法
2.5 Transclution
维基百科:在计算机科学中,Transclusion是指将整个或部分文档通过超文本引用包含到其他单个或多个文档中。
ng-transclude指令的作用其实就是把指令开始标签与结束标签之间的内容插入ng-transclude所在的位置。
transclude: element
该种情况表示把指令所作用的元素一同嵌入到ng-transclude指令所在的位置。此外,transclude属性默认为false。
更高级的使用暂未学习。