angular也用了大半年了,写个文章总结一下一些重要的机制吧。
angular1.x版本中的一个一个重要特性就是指令(Directive)。指令功能十分强大,他的作用简单来说就是可以给HTML元素赋予特殊或自定义的行为,比如监听事件、视图模板代理等。
指令的形式
在AngularJS中,指令有四种表现形式:
- E(元素):
<directiveName></directiveName>
- A(属性):
<div directiveName='expression'></div>
- C(类):
<div class='directiveName'></div>
- M(注释):
<--directive:directiveName expression-->
可以在创建指令时通过设置restrict属性来定义指令的形式,一个指令可以同时有多种表现形式,Angular 1.3 +默认使用EA。
指令的命名
一般情况下在定义指令时推荐使用驼峰命名法,比如ngModel、ngApp,但是在HTML中大小写是不敏感的,所以在HTML中使用指令时推荐使用小写字母加破折号的形式,比如ng-model
、ng-app
。
除了使用小写破折号这种方式,还有以下几种使用写法比较少用:
- ng:model
- ng_model
- data-ng-bind
- x-ng-bind
创建指令
指令也是通过AngularJS的Model创建的,使用directive(name, directiveFactory)
方法创建指令,第一个参数是指令名称,第二个参数是一个工厂函数,该函数需要返回一个对象,通过配置该对象中的不同属性从而令AngularJS内置的$compile服务实现指令的不同功能。
下面是一个创建指令的简单demo( 来源 )
|
|
|
|
在HTML页面中使用:<div my-example max="77"></div>
指令属性配置
下面详细介绍各个可配置的属性:
restrict
上文已经介绍了指令的四种形式,restrict属性用于指定指令的形式,一个指令可以存在多种形式.例如restrict:'EA'
则表示指令在DOM里面可用元素形式和属性形式被声明,如果想支持IE8,最好使用属性和类形式来定义。
template:
指定一个内嵌模板,可以使字符串(一段HTML文本)或者函数。当为函数时,可接受两个参数tElement和tAttrs。第一个参数代表当前的HTML DOM元素,而第二个参数为实例的属性,它是一个由元素上所有的属性组成的集合(对象)
templateUrl
指定模板加载的URL,当已经设置template时不会生效。
由于加载html模板是通过异步加载的,若加载大量的模板会拖慢网站的速度。
可以通过先缓存模板来加快加载模板的速度。
当模板很多时,可以通过给模板指令设置相关属性,从而动态的加载UI模板文件:
scope
该属性用于配置指令的作用域。关于AngularJS作用域的详细说明可以参考 AngularJS作用域Scope的继承
- 默认值false:表示继承父作用域;
除非该directive与html不存在数据绑定,一般情况下建议使用后几种方式。 - true:表示继承父作用域,并创建自己的作用域(子作用域);
directive创建一个子作用域, 并且会从父作用域进行原型继承。
如果同一个DOM element存在多个directives要求创建子作用域,那么只有一个子作用域被创建,多个directives将共用该子作用域。 - {}:表示创建一个全新的隔离(Isolate)作用域,没有原型继承。
这是创建可复用directive组件的最佳选择。因为它不会直接访问/修改父作用域的属性,不会产生意外的副作用。这种directive与父作用域进行数据通信有如下几种方式,如果绑定的隔离作用域属性名与元素的属性名相同,则可以采取缺省写法(前)。- = or =attr “Isolate”作用域的属性与父作用域的属性进行双向绑定,
任何一方的修改均影响到对方,这是最常用的方式; - @ or @attr “Isolate”作用域的属性与父作用域的属性进行单向绑定,
即“Isolate”作用域只能读取父作用域的值,并且该值永远的String类型;12345678910app.controller('MainController',function(){});app.directive('helloWorld',function(){return {scope: {color:'@colorAttr'}, //指明了隔离作用域中的属性color应该绑定到属性colorAttrrestrict: 'AE',replace: true,template: '<p style="background-color:">Hello World</p>'}});<hello-world color-attr=''></hello-world>
- & or &attr “Isolate”作用域把父作用域的属性包装成一个函数,可用于调用父作用域的函数,包装方法是$parse,详情请见 API-$parse ;
“Isolate”作用域的proto是一个标准Scope object (the picture below needs to be updated to show an orange ‘Scope’ object instead of an ‘Object’.)“Isolate”作用域的$parent同样指向父作用域。它虽然没有原型继承,但它仍然是一个子作用域。
如下directive:<my-directive interpolated="" twowayBinding="parentProp2">
scope: { interpolatedProp: '@interpolated', twowayBindingProp: '=twowayBinding' }
link函数中:scope.someIsolateProp = "I'm isolated"
请注意,我们在link函数中使用attrs.$observe(‘interpolated’, function(value) { … }来监测@属性的变化。
更多请参考 这里
- = or =attr “Isolate”作用域的属性与父作用域的属性进行双向绑定,
transclude
(布尔值或者字符‘element’),默认值为false;用于设置是否开启指令的内嵌机制。
如果为true,directive会新建一个“transcluded”子作用域,并且会从父作用域进行原型继承。
指令标签之间的内容可以被指定嵌入UI模板中被ng-transclude内置指令标记过的DOM元素中。
|
|
生成html时可以发现文本“你看不见我”被transclude内容替换掉了。
‘element’与true的区别?
当transclude:true时候,嵌入的内容为,而当transclude:“element”时候,嵌入的内容为
<hello-world></hello-world>
。需要注意的是,当transclude设置为‘element’时,指令的repalce属性需要设置为true,详见 这里 。
replace
当被设置为true时,渲染出来的HTML会替换原标签。
priority
一个数字,用于设置该指令优先级,若在单个DOM上有多个指令,则优先级高的会先执行,
angularjs内置指令的ng-repeat的优先级为1000,ng-init的优先级为450。不常用。
terminal
布尔类型,若设置为true,则优先级低于此指令的其他指令则无效,不会被调用(优先级相同的还是会执行)
controller
可以是一个字符串或者函数。若是为字符串,则将字符串当做是控制器的名字,来查找注册在应用中的控制器的构造函数。
和在Module中创建Controller很类似,可以在参数中注入需要的AngularJS服务,和Module中的Controller相比,指令中的Controller有一些特殊的服务(参数)可以注入
(1)$scope,与指令元素相关联的作用域
(2)$element,当前指令对应的元素
(3)$attrs,由当前元素的属性组成的对象
(4)$transclude,嵌入链接函数,实际被执行用来克隆元素和操作DOM的函数(不建议写在Controller中,DOM操作最好写在link中)
controller和后面会介绍到的link函数非常相似,但其实两者职能不同。
controllerAs
指定Controller的名称,和view使用controller as保持一致,注意:当你把controller注入到link的函数或可访问的directive的attributes时,你可以把它命名为控制器的属性。function linkFunc(scope, el, attr, vm) //把vm直接传递进来
bindToController
当directive中使用了controller as语法时,如果你想把父级作用域绑定到directive的controller作用域时,使用bindToController = true。这使得把外部作用域绑定到directive controller中变得更加简单。
注意:Angular 1.3.0才介绍了bindToController。
require
字符串或者数组。
指令之间的交互主要是以指令的Controller为桥梁来实现的,这里的交互指的是子指令与父指令之间的交互,我们可以使用指令的require属性设置要引用的父指令的Controller,
这里有几种配置方式:
require: "controllerName"
:只查找指令自己的Controller,如果找不到任何控制器,则会抛出一个error。require: "?controllerName"
:只查找指令自己的Controller,如果找不到任何控制器,则会将null传给link连接函数的第四个参数。require: "^controllerName"
:查找指令自己的Controller以及父指令的Controller。require: "^^controllerName"
:只查找父指令的Controller。require: ["^controllerName1", "^controllerName2"]
:引用多个Controller。
link
link函数主要用来为DOM元素添加事件监听、监视模型属性变化、以及更新DOM。会晚于controller函数执行。
该函数共有五个参数:
- scope:指令的作用域,默认是父节点Controller的作用域,如果指令有创建自己的作用域,那么则指指令自己的作用域。
- element:指令的jQLite(jQuery的子集)包装的DOM元素,可以通过该参数操作指令所在的DOM元素。
- attrs:指令所在DOM元素的属性对象,通过.语法可以获取到给DOM元素添加的属性。
- controller:指令通过require属性引用的Controller实例。
- transcludeFn:嵌入函数。
通过指令操作DOM元素: