AngularJS使用directive自定义指令
directive
除了AngularJS的内置指令,我们也可以通过.directive
来创建自定义的指令。
app.directive("myDir",function(){ return { template:"这是自定义指令
" } })
命名
AngularJS要求自定义的Directive
命名使用驼峰式语法。也就是从第二个单词开始,每个单词首字母大写,并且不用任何连接符号。
命名 | 使用 |
---|---|
dir | dir |
myDir | my-dir |
myDirArray | my-dir-array |
参数
restrict:String, priority:Number,terminal:Boolean,template:String or Template Function,templateUrl:String or Template Function,replace:Boolean or String,transclude:Boolean,scope:Boolean or Object,controller:String or function(scope, element, attrs, transclude, otherInjectables) { ... },controllerAs:String,require:String,link: function(scope, iElement, iAttrs) { ... },compile:function(tElement, tAttrs, transclude) { return { pre: function(scope, iElement, iAttrs, controller) { ... }, post: function(scope, iElement, iAttrs, controller) { ... } } return function postLink(...) { ... } }
这里是Directive
的所有参数,下面我们主要介绍一下常用的参数restrict
,template
,scope
,link
,compile
组合使用例子
restrict
restrict
描述了我们怎么使用自定义指令,以上面自定义的myDir
为例
参数 | 使用 |
---|---|
E(Element) | <my-dir></my-dir> |
A(attribute) | <div my-dir></div> |
C(class) | <div class="my-dir"></div> |
EAC
可以组合使用
scope
scope
:为directive
指定相关联的作用域
参数 | 使用 |
---|---|
false(默认值) | 将使用parent 的scope ;改变scope 中的值,directive 的值也会发生变化,反之亦如此 |
true | 创建一个继承parent``scope 的子scope ;改变parent``scope 中的值,子scope 会发生变化;改变子scope 中的值,parent``scope 不会发生变化 |
{} | 创建一个独立的scope ,可以使用 @ = & 和parent``scope 进行属性绑定;不继承parent``scope 改变任何一方都不影响对方 |
false和true
- 我们点击
button
会发现directive E``directive C
的值都会发生变化,
- 修改
age
对应的input框只有directive C
的age会发生变化
@
=
&
scope
为{}
时,用三者的主要区别为
type | describe |
---|---|
@ (@attr) | Text binding / one-way binding |
= (=attr) | Direct model binding / two-way binding |
& | Behaviour binding / Method binding |
@
传递的是字符串不是对象
//html//directive scope:{ name:"=newName", age:"@nawAge", changeAge:"&" }
两种写法是相同的
@
也可以定义在link
.directive("myDir", function() { return { template:""+ " name:"+ " age:"+ " { {age}}"+ "", restrict:"E", scope:{ name:"=", /*age:"@",*/ changeAge:"&" }, link:function(scope, iElement, iAttrs){ //scope.age = iAttrs.age; 这么写 只有在第一次加载的时候等于`scope age`但是不会随着changeAge事件更新 iAttrs.$observe('age', function(value) { scope.age = value; }) } };});
- 如果用使用&绑定函数传参数需要json 否则会报错
TypeError: Cannot use 'in' operator to search for 'editWebsite' in 1
template:""+ " name:"+ " age:"+ " { {age}}"+ ""
compile、link
在使用前我们先简单了解一下下面两个阶段-编译和链接阶段
第一个阶段是编译阶段,AngularJS会递归的遍历DOM,并从JavaScript中的指令定义知道需要执行的操作。
如图(from stackoverflow)所示原始DOM模板作为函数的参数传给compile
编译函数,编译后会返回它的实例。我们有机会在它被返回前对DOM模板进行操作。
1.1 我们以ng-repeat
为例,HTML中生成的重复元素就是DOM模板的实例。实例有多个但是模板元素只有一个。
第二个阶段是链接阶段,链接函数link
将模板与作用域链接起来。负责设置事件监听器、监视数据变化和实时的DOM操作。
如果定义了编译函数
compile
它会返回pre-link
和post-link
函数如果只定义了链接函数
link
,则会被视为post-link
If you create a directive that only has a link function, AngularJS treats the function as a post-link function. Hence the reason to discuss it here first.
post-link
会和前面DOM遍历相反的顺序调用。这个顺序保证所有子元素的post-link
在父元素post-link
运行时都已经被执行了。
pre-link
是AngularJS提供了一个额外的钩子。它可以让你在子元素的post-link
函数之前运行你的代码。
所以这里是自定义指令最常用的地方,大多数情况下我们只需要编写
post-link
被认为是最安全的,因为此时所有子元素都已经被编译compile
并且所有子元素的pre-link
和post-link
都已经执行结束。link
函数即可
.directive("myDir", function() { return { template:"{ {info.name}}:"+ "{ {info.age}}", restrict:"E", compile:function(tELe ,tAttrs,transcludeFn){ return{ // 子元素被链接之前执行 pre:function(scope, iElement, iAttrs, controller){}, // 子元素被链接之后执行 post:function(scope, iElement, iAttrs, controller){ // 绑定DOM事件 iElement.on('click',function(){ scope.$apply(function(){ scope.infoList[0].name += "_"; scope.infoList[0].age ++; }); }); } } } };});
等于下面这种写法
.directive("myDir", function() { return { template: "{ {info.name}}:" + "{ {info.age}}", restrict: "E", link: function(scope, iElement, iAttrs) { iElement.on('click', function() { scope.$apply(function() { scope.infoList[0].name += "_"; scope.infoList[0].age++; }); }); } }; });