API
app.directive('helloWorld', function() {
return {
restrict: string,
priority: number,
template: string,
templateUrl: string,
replace: bool,
transclude: bool,
scope: bool or object,
require: string,
controller: function (scope,elem,attrs,transclude){},
compile: function(){
return {
pre: function(scope, iElem, iAttrs){
},
post: function(scope, iElem, iAttrs){
}
}
},
link: function(scope, elem, attrs) {},
};
});
restrict: 指令运用时显示的方式
priority: 一条语句中包含了多条指令时,执行的先后顺序
template: 字符串作为模板
templateUrl: 指定url页面作为模板
replace: 是否替换指令所在元素
transclude: 把指令元素中原来的子节点移动到一个新的模板内部
scope:新的作用域
require:必须存在另外的指令,此指令才执行
controller:控制器
compile: 编译函数
link: 链接函数
restrict
restrict是用来表明使用指令的方式,共有E、A、C、M四种风格。
app.directive('directiveTest', function () {
return {
restrict: 'EACM',
template: '<div>test</div>'
};
});
使用
<!--E方式-->
<directive-test></directive-test>
<!--A方式-->
<div directive-test></div>
<!--C方式-->
<div class="directive-test"></div>
<!--M方式 我使用的1.3版本没有作用-->
<!-- directive: directive-test -->
priority
当我们在一条语句中使用了多个指令时,需要进行执行顺序优先级的判断,默认值为0,例如:
app.directive('directiveOne', function () {
return {
restrict: 'A',
priority:1,
template: '<div>one</div>'
};
});
app.directive('directiveTwo', function () {
return {
restrict: 'A',
priority:2,
template: '<div>two</div>'
};
});
使用
<div directive-one directive-two></div>
结果页面只会显示two,因为先执行directiveTwo(此处两个指令功能冲突)。
<div directive-one="" directive-two=""><div>two</div></div>
template与templateUrl
template与templateUrl都是进行模板定义,区别在于一个使用字符串,一个引用url地址。
app.directive('directiveOne', function () {
return {
restrict: 'A',
template: '<div>one</div>',
templateUrl: 'xxx/xxxx/test.html'
};
});
当template与templateUrl同时存在时,系统会选择使用template。
replace
replace用于是否替换指令所在元素。
app.directive('directiveOne', function () {
return {
restrict: 'A',
template: '<div>one</div>',
replace:true
};
});
replace false(默认值):
<div directive-one="" class="ng-scope"><div>one</div></div>
replace true:
<div directive-one="" class="ng-scope">one</div>
transclude
transclude是否使用原有内容,通过ng-transclude调用。
app.directive('directiveOne', function () {
return {
restrict: 'A',
template: '<div>one<span ng-transclude></span></div>',
transclude:true
};
});
<div directive-one>原有内容</div>
结果
<div directive-one="" class="ng-scope">
<div>
one
<span ng-transclude="">
<span class="ng-scope">原有内容</span>
</span>
</div>
</div>
one原有内容
注意:ng-transclude不能放在根dom中,例如下面是会报错的
template: '<div ng-transclude></div>',
compile与link
compile与link是对dom的操作支出,也是指令的核心点。compile侧重于对模板本身进行操作,而link侧重于模板与数据进行关联。
首先我们需要了解angular初始化分为三个步骤:加载脚本,编译阶段,链接阶段
- 加载脚本:加载angular库,查找ng-app确定边界。
- 编译阶段:遍历dom,识别template、replace等进行dom的转化,执行compile函数。
- 链接阶段:运行link函数,对dom进行监听。
compile函数包含两个返回函数
compile: function(){
return {
pre: function(scope, iElem, iAttrs){
},
post: function(scope, iElem, iAttrs){
}
}
},
- pre:函数能够保证在element实例上以及它的所有子指令的post运行之前执行。
- post:当ng遍历完所有的dom并运行完所有的compile函数之后,就反向调用相关联的post函数.
- compile只会调用一次,而link调用次数与调用次数相关(一个page内)。
也就是当同一个dom存在多条指令时,directiveOne、directiveTwo、directiveThree,执行顺序如下:
directiveOne.compile->directiveTwo.compile->directiveThree.compile
->directiveOne.pre->directiveTwo.pre->directiveThree.pre
->directiveThree.post->directiveTwo.post->directiveOne.post
link函数
link: function(scope, elem, attrs) {},
我测试的测过好像是link与compile不能共存
controller
是创建一个改dom为边界的controller层。
controller:'controllerName'
或者是
controller:function($scope, $element,$attrs,$transclude){
}
require
通过require属性语法,其他指令可以把这个控制器传递给自己。
形式:require:’^?directiveName’
- directiveName:驼峰法则命名制定控制器带有哪条指令。
- ^:默认是从同一个元素的命名指令中获取控制器。添加这个之后,遍历dom树进行查找
- ?:如果没有找到控制器,会抛出异常,添加之后,则不会抛出异常。
举例如下:
app.directive('out', function () {
return {
restrict: 'EA',
transclude:true,
replace:true,
template: '<div><div ng-transclude></div></div>',
controller:function($scope, $element,$attrs,$transclude){
this.print = function(){
console.log("parent")
}
}
};
});
app.directive('in', function () {
return {
restrict: 'EA',
transclude:true,
replace:true,
require:'^?out',
template: '<div><div ng-click="print()">click(点击)</div>' +
'<div ng-transclude></div></div>',
link:function(scope,element,attrs,ctrl){
scope.print = function(){
console.log("self");
ctrl.print();
}
}
};
});
运用
<out>
<in></in>
</out>
效果
click(点击)
控制台输出:
self
parent
scope
scope可以定义scope的作用域,有三种类型
- scope:fasle(默认值),scope为dom元素上原有的scope对象。
- scope:true,新创建一个scope对象,继承外层scope。
- scope:{xxxx},独立scope对象,不会继承外层scope。
false:
继承外层scope:指令中对scope进行修改,也会修改外层scope对象数值。
app.directive('directiveOne', function () {
return {
restrict: 'A',
template: '<div>one </div>'
};
});
app.controller('testCtrl', function ($scope, $http, $location, $rootScope) {
$scope.data ="controller定义的内容"
})
<div ng-app="testCtrl">
<div directive-one></div>
</div>
结果
one controller定义的内容
true:
继承外层scope:指令中对scope进行修改,则不会改变外城scope,实际上是创建了一个新的域,只是指令初始化时使用了外层scope的对象数值。
{xxxxx}
在我看来这个作用就是可以从指令dom上获取数据。
绑定策略:
- @: 把当前属性作为字符串进行传递
- =: 读取父scope的一个对象
- &: 传递一个父scope的函数
例如:
app.controller('testCtrl', function ($scope, $http, $location, $rootScope) {
$scope.data ="controller定义的内容"
$scope.fun = function(){
console.log("this is a function")
}
})
<div ng-app="testCtrl">
<div directive-one str="" data="data" fun="fun()"></div>
</div>
app.directive('directiveOne', function () {
return {
restrict: 'A',
template: '<div>@:</div><div>=:</div><div ng-click="fun()">fun</div>',
scope:{
str:'@str',
data:'=data',
fun:'&fun'
}
};
});
结果
@:controller定义的内容
=:controller定义的内容
fun
控制台(点击fun)
this is a function