1. 通过 module.directive(name,directiveFactory) 定义 , 如:
(function() {
angular.module('starter')
.directive('myCustomer', function() {
return {
restrict: 'E',
templateUrl: 'directiveTest/my-customer.html'
};
})
})()
2. 注入 $compileProvider ,通过 $compileProvide.directive() 定义 , 如:
var myApp = angular.module('myApp', [], ['$compileProvider',function ($compileProvider) {
$compileProvider.directive('customTags',function(){
return {
restrict:'ECAM',
template:'custom-tags-html',
replace:false
}
});
}])
【二】 restrict 、 template 、 replace、templateUrl属性
var myApp = angular.module('myApp', [], ['$compileProvider',function ($compileProvider) {
// 如果指令的名字为xxx-yyy 在设置指令的名字时应为 xxxYyy 驼峰式命名法
$compileProvider.directive('customTags',function(){
return {
restrict:'ECAM',
template:'custom-tags-html',
replace:false,
// templateUrl :加载模板所要使用的URL
//replace :如果为true 则替换指令所在的元素,如果为false 或者不指定,则把当前指令追加到所在元素的内部
//restrict :指令在模板中的使用方式
//可以4种风格任意组合,如果忽略restrict,默认为A
// E : 风格为 元素 (作为标签名) 使用方式: 1212
// C: 风格为 样式类 使用方式:
// A : 风格为 属性 使用方式:
// M : 风格为 注释
// 注意:当有两个directive的时候 只能有一个template,否则会报错
}
});
}])
【三】transclude、priority、terminal 属性
priority : 设置指令在模板中的执行顺序,顺序是相对于其他元素上的指令而言,默认为0,从大到小的顺序一次执行
terminal : 是否以当前指令的权重为结束界限。如果这个值设置为true,则节点中权重小于当前指令的其他指令不会被执行。相同权重的会执行
.directive('customTags', function () {
return {
restrict: 'ECAM',
template:'新数据 ',
replace: true,
transclude:true
//transclude:为true时,指令元素中的原来的子节点移动到一个新模板内部(移动到的位置通过ng-transclude确定)
//priority 设置优先级
}
})
.directive('customTags2', function () {
return {
restrict: 'ECAM',
template:'2',
replace: true,
priority:0
}
})
.directive('customTags3', function () {
return {
restrict: 'ECAM',
template:'3',
replace: true,
priority: 1,
// terminal 为true 时 priority 小于当前指令的priority的directive 都不会执行
terminal:true
}
})
【四】 compile 和 link 属性
Angularjs 指令编译三个阶段
1.标准浏览器API转化
将html 转化成dom ,所以自定义的html 标签必须符合html 的格式
2.Angular compile
搜索匹配 directive ,按照priority排序,并执行directive上的compile 方法
3.Angular link
执行directive上的link 方法,进行 scope绑定及事件绑定
link 函数负责在模型和视图之间进行动态关联
.directive('customTags',function(){
return {
restrict : 'ECAM',
template : '{{user.name}}',
replace : true,
compile:function(tElement,tAttrs,transclude){
// 1.编译阶段...主要可以进行DOM 结构的操作
// tElement.append(angular.element('{{user.name}}{{user.count}}'));
console.log('customTags compile 编译阶段...');
return {
//2.Link 包括 pre 和 post 主要可以用在添加事件的绑定和scope绑定
// 2.1.1表示在编译阶段之后,指令连接到子元素之前运行
pre:function preLink(scope,iElement,iAttrs,controller){
console.log('customTags preLink..')
},
// 2.1.2表示在所有子元素指令都连接之后才运行
post:function postLink(scope,iElement,iAttrs,controller){
iElement.on('click',function(){
//需要用 $apply触发一次 脏检查
scope.$apply(function(){
scope.user.name = 'click after';
scope.user.count = ++i;
});
})
console.log('customTags all child directive link..')
}
}
// 也可以直接返回 postLink
// return function postction(scope,iElement,iAttrs,controller){
// console.log('compile return fun');
// }
},
// 此link表示的就是 postLink
// link:function postction(scope,iElement,iAttrs,controller){
// iElement.on('click',function(){
// scope.$apply(function(){
// scope.user.name = 'click after';
// scope.user.count = ++i;
// // 进行一次 脏检查
// });
// })
// }
}
})
【五】controller 、controllerAs 和 require 属性
.directive('bookList', function() {
return {
restrict: 'ECAM',
// controller 会暴露一个API ,利用这个API 可以在多个指令之间通过依赖注入进行通信
controller: function($scope) {
$scope.books = [{
name: 'php'
}, {
name: 'javascript'
}, {
name: 'java'
}];
this.addBook = function() {
$scope.$apply(function() {
$scope.books.push({
name: 'Angularjs'
})
});
}
},
controllerAs: 'bookListController',//controllerAs:给上面的controller 起个别名
template: '- {{book.name}}
',
replace: true
}
})
.directive('bookAdd', function() {
return {
restrict: 'ECAM',
require: '^bookList',
//require 可以将其他指令传递给自己 ,如此可以去调用其他的指令的函数和修改其他指令的字段,实现不同指令之间的通信
// (没有前缀)如果没有前缀,指令将会在自身所提供的控制器中进行查找,如果没有找到任何控制器就抛出一个错误。
// ? 如果在当前指令中没有找到所需要的控制器,会将null作为传给link函数的第四个参数。
// ^ 如果添加了^前缀,指令会在上游的指令链中查找require参数所指定的控制器。
// ?^ 将前面两个选项的行为组合起来,我们可选择地加载需要的指令并在父指令链中进行查找。
template: '',
replace: true,
link: function(scope, iElement, iAttrs, bookListController) {
//点击调用第一个指令的addBook函数
iElement.on('click', bookListController.addBook);
}
}
})
【六】 scope 属性
scope : 为当前指令创建一个新的作用域
false : 继承父元素的作用域
true : 创建一个新的作用域
参数:
&:作用域把父作用域的属性包装成一个函数,从而以函数的方式读写父作用域的属性
=: 作用域的属性与父作用域的属性进行双向绑定,任何一方的修改均会影响到对方
@:只能读取父作用域里的值单项绑定
.directive('bookList', function () {
return {
restrict: 'ECAM',
controller: function ($scope) {
$scope.books = $scope.a();
$scope.books = $scope.b;
$scope.b.push({name:'nodejs'});
console.log($scope.c);
},
// 创建一个有继承链的独立作用域
// scope:true,
// 当scope 为对象的时独立的作用域候也会创建一个
scope:{
// 将父元素books封装成一个a函数(&:作用域把父作用域的属性包装成一个函数,从而以函数的方式读写父作用域的属性)
a:'&books'
// 双向绑定 b = parentBooks属性对应的父作用域的表达式(=:作用域的属性与父作用域的属性进行双向绑定,
// 任何一方的修改均会影响到对方)
b:'=parentBooks'
// 只能使用简单数据类型的方法,不能用对象(@ :只能读取父作用域里的值单向绑定)
c:'@parentTitle'
},
controllerAs:'bookListController',
template: '- {{book.name}}
',
replace:true
}
})
.controller('firstController', ['$scope', function ($scope) {
console.log($scope);
$scope.books = [
{
name: 'php'
},
{
name: 'javascript'
},
{
name: 'java'
}
];
$scope.title = '张三';
}]);
注意:html 文件中的属性写法要与指令中定义的相匹配。以上面的为例,html中: