0、使用
var app = angular.module('myApp', []);
1、require属性
在自定义Angular指令时,其中有一个叫做require的字段,这个字段的作用是用于指令之间的相互交流。
举个简单的例子,假如现在需要编写两 个指令,在linking函数中有很多重合的方法,为了避免重复自己(著名的DRY原则),可以将这个重复的方法写在第三个指令的 controller中,然后在另外两个需要的指令中require这个拥有controller字段的指令,最后通过linking函数的第四个参数就可以引用这些重合的方法。
var app = angular.modeule('myapp',[]);
app.directive('common',function(){
return {
...
controller: function($scope){
this.method1 = function(){
};
this.method2 = function(){
};
},
...
}
});
app.directive('d1',function(){
return {
...
require: '?^common',
link: function(scope,elem,attrs,common){
scope.method1 = common.method1;
..
},
...
}
});
link的第四个参数指向require的指令的控制器
<body>
<div ng-app="myApp">
<div ng-controller="myCtrl">
<book-list></book-list>
</div>
</div>
<script>
angular.module('myApp',[])
.directive('bookList',function(){
return {
restrict:'E',
template:'<div><ul><li ng-repeat="book in books">{{ book.name }}</li></ul><book-add></book-add></div>',
replace:true,
controller:function($scope){
$scope.books=[
{name:'book01'},{name:'book02'},{name:'book03'}
];
this.addBook=function(name){
if(typeof(name)=='undefined' || name.length<1){alert('书名不可为空!');return;}
$scope.$apply(function(){
var exist=false;
angular.forEach($scope.books,function(ele,i){
if(ele.name == name){
exist=true;
return;
}
});
if(exist){alert('该书已经存在!')}else{
$scope.books.push({name:name});
}
});
}
},
controllerAs:'bookListController'
}
})
.directive('bookAdd',function(){
return {
restrict:'E',
template:'<div><input type="text" placeholder="书名" ng-model="newBookName"><button type="button">添加</button></div>',
replace:true,
require:'^bookList',
link:function(scope,iElement,iAttrs,bookListController){
iElement.find('button').on('click',function(){
bookListController.addBook(scope.newBookName);
})
}
}
})
.controller('myCtrl',function($scope){});
</script>
</body>
https://blog.csdn.net/xuanwuziyou/article/details/52885559
校验:
require:'ngModel'
angular.module('soc.app.pivot').directive('validateIpPort', function(){
return {
restrict: 'A',
require: 'ngModel',指令定义只会查找定义在指令当前用域中的ng-model="" 只会对使用这个指令的mg-model有效
这个ng-model里的变量会作为link的第四个参数 其实第四个参数是指向指令的控制器,而ngModal指令的控制器就是ng-modal双向绑定的值
link: function(scope, element, attrs, ngModelCtrl){
function validator(input)
{
var regExp = /^((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])([:]\d{1,5})?)?$/;
var valid = regExp.test(input);
ngModelCtrl.$setValidity('ipPort', valid);
return valid ? input: undefined;
}
ngModelCtrl.$parsers.push(validator);
}
};
});
用到了$parsers这个属性和$setValidity()这个方法。 $parsers里保存了一组function, 每当DOM里数据变化的时候, 这组function会被一次调用。这里给了我们机会在用户修改了DOM里值的时候, 去对新输入的值做校验。
使用:
<form class="form-horizontal" name="eventConfig">
<div class="title-brand">事件白名单配置</div>
<div class="form-group">
<label class="col-md-2 control-label">
<abbr>事件对象</abbr>
</label>
<div class="col-md-3">
<input type="text" name="eventObject" class="form-control" validate-ip-port ng-model="eventObject"/>
</div>
<div class="addEventConfig-error-tips" role="alert" ng-show="eventConfig.eventObject.$dirty&&eventConfig.eventObject.$error.ipPort">好像必须form的name 加input的name
<i class="fa fa-times-circle"></i>
<span>ip地址格式错误</span>
</div>
使用是form表单的name.input的name.$error.$setValidity()定义的key
2、restrict属性
模块.directive(‘指令名’,function(){
return{
restrict: 'A':属性, 'E':元素(标签), 'C':样式,'M':注释
}
})
3、link属性
link通过代码修改目标DOM元素的实例,添加事件监听,建立数据绑定。compile函数用来对模板自身进行转换,而link函数负责在模型和视图之间进行动态关联;compile函数仅仅在编译阶段运行一次,而对于指令的每个实例,link函数都会执行一次;compile可以返回preLink和postLink函数,而link函数只会返回postLink函数,如果需要修改DOM结构,应该在postLink中来做这件事情,而如果在preLink中做这件事情会导致错误;大多数时候我们只要编写link函数即可。
link函数有四个参数分别为:
(1)scope,与指令元素相关联的作用域
(2)element,当前指令对应的 元素
(3)attrs,由当前元素的属性组成的对象
(4)supermanCtrl,若指令中定义有require选项,则会有supermanCtrl参数,代表控制器或者所依赖的指令的控制器。
4、scope
我们之所以要定义指令,目的是重用指令。假设有这么一个应用场景:在同一个html里使用了两次my-directive,第一个my-directive要展示的是Hello World,第二个my-directive要展示的是Hello AngularJs。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<script src="../lib/angular-1.3.16/angular.min.js"></script>
<script src=""></script>
<title></title>
<script language="JavaScript">
angular.module('app',[])
.directive('myDirective',function(){
return{
template:'Hello {{greeting}}!',
scope:{
greeting:'@'
}
};
});
</script>
</head>
<body ng-app="app">
<div my-directive greeting="World"></div>
<div my-directive greeting="AngularJs"></div>
</body>
</html>
@:单向绑定 父改变 子也改变 子改变但是父不改变 变量外面必须加{{}}
= :双向绑定 变量外不加{{}}
& :针对方法
<script src="https://cdn.staticfile.org/angular.js/1.4.6/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="myController">
<div ng-controller="myController">
<div>父scope:
<div>Say:{{user.name}}<br>改变父scope的name:<input type="text" value="" ng-model="user.name"/></div>
<input type="number" ng-model="age">
<!--<input type="number" ng-model="age2">-->
</div>
<div>隔离scope:
<div isolated-directive user="user" age="age"></div>
</div>
<div>隔离scope(使用{{name}}):
<div isolated-directive user="{{user}}" age="{{age}}"></div>
</div>
<!--<div>隔离scope(使用{{name}}):-->
<!--<div isolated-directive user="user" age="age2"></div>-->
</div>
</div>
</div>
<script>
var app = angular.module('myApp', []);
app.controller("myController", function ($scope) {
$scope.age=12;
$scope.age2=15;
$scope.user = {
name: 'hello',
id: 1
};
}).directive("isolatedDirective", function () {
return {
scope: {
user: "=",
age:"="
},
template: `Say:{{user}} <br>改变隔离scope的name:<input type="buttom" value="" ng-model="user.name"/>
age:{{age}} <input type="text" ng-model="age">
`
}
})
@好像不能对变量是对象的进行绑定,比如上面的user
=好像有的时候不能有作用,比如上面的age
若在子控制器(同样包括在指令中的link或是controllerding中定义变量,此时指令中必须未使用scope独立作用域)未定义相关变量,那么它会向父控制器一层层查找,直到找到位为止。
程序是按照控制器->指令中的link->指令中的controller 的顺序来运行的
var myApp=angular.module("myApp",[]);
myApp.controller("test",["$scope",function($scope){
$scope.param="moudelController-param";
}]);
myApp.directive("dirScope",function(){
return{
restrict:"AE",
template:"<div>{{param}}</div>",
replace:true,
controller:function($scope,$element,$attrs){
$scope.param="dirController-param";
},
link:function(scope,ele,attrs){
console.log("link param:" + scope.param);
ele.bind("click",function(){
scope.param="link-param";
scope.$apply();
console.log("link click param:" + scope.param);
})
}
}
})
在指令的controller中对param赋的值覆盖了模块下的控制器对param赋的值,在指令中的link阶段同样输出的是“dirController-param”,说明模块下的controller与指令的controller、link中定义的同名变量为同一变量。
点击页面中的“dirController-param”触发的变化同样说明了这个问题,一下为点击“dirController-param”后的界面:
上面的和scope:param:"=" 是一个结果,指令中这个变量改变,控制器中的这个变量也随之改变
有一种情况,就是$scope.event.eventName需要把event.eventName传给一个新的变量里,随指令传给指令的作用域,然后scope = 才可以
var myApp=angular.module("myApp",[]);
myApp.controller("test",["$scope",function($scope){
$scope.param="moudelController-param";
}]);
myApp.directive("dirScope",function(){
return{
restrict:"AE",
scope:{
param:"@"
},
template:"<div>{{param}}</div>",
replace:true,
controller:function($scope,$element,$attrs){
$scope.param="dirController-param";
},
link:function(scope,ele,attrs){
console.log("link param:" + scope.param);
ele.bind("click",function(){
scope.param="link-param";
scope.$apply();
console.log("link click param:" + scope.param);
})
}
}
})
在页面中,模块下控制器与指令中显示的不同,说明模块下控制器中的param与指令中的param互为独立的(可以理解为两个不同的变量,因为当指令中使用独立作用域scope时,若在指令中未定义该变量则不会向父控制器查找同名变量)。然而在控制台输出了在指令中link阶段param的值为 dirController-param,说明指令中的link、controller使用的为同一变量,当点击页面中的“dirController-param”会触发在指令link阶段定义的click事件,触发结果也说明了模块下控制器中的变量与指令中的同名变量互为独立的。
5、transclude
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<script src="../lib/angular-1.3.16/angular.min.js"></script>
<script src=""></script>
<title></title>
<script language="JavaScript">
angular.module('app',[])
.directive('myDirective',function(){
return{
template:'<div>\
<h2>大标题</h2>\
<span ng-transclude></span>\
</div>',
transclude:true
};
});
</script>
</head>
<body ng-app="app">
<div my-directive >
<ul>
<li>小标题1</li>
<li>小标题2</li>
</ul>
</div>
</body>
</html>
<script src="../lib/angular-1.3.16/angular.min.js"></script>
<script src=""></script>
<title></title>
<script language="JavaScript">
angular.module('app',[])
.directive('myDirective',function(){
return{
restrict:'E',
template:'<div>\
<h2>大标题</h2>\
<span ng-transclude></span>\
</div>',
transclude:true
};
})
.directive('myDirective2',function(){
return{
restrict:'E',
template:'<div>\
<h3>中标题</h3>\
<span ng-transclude></span>\
</div>',
transclude:true
};
});
</script>
</head>
<body ng-app="app">
<my-directive>
<my-directive2>
<ul>
<li>小标题1</li>
<li>小标题2</li>
</ul>
</my-directive2>
</my-directive>
2、自定义指令
指令引入:
在定义模块的js引入定义指令的js即可使用
在index.js中定义模块
angular.module('soc.app.event',[依赖])
在index.js中引入要使用的指令所定义在的js文件
require('./eventRule/eventCheckbox.directive.js');
定义指令时要定义在模块下
在文件eventCheckbox.directive.js中
angular.module('soc.app.event').directive('checkAllHandle', checkAllHandle);
指令写法:
使用:
<input type="checkbox" id="chkAll" check-all-handle relate-data="dataRuleList">
function checkAllHandle() {
return {
scope: {
relateData: '=' 这个是在指令后面的属性
},
link: function (scope, element) {
$(element).bind('click', function () {
dataRulrList是别的定义好的,relate-data="dataRuleList",
现在scope.relateData是dataRulrList的值
$(element)会返回当前被点击的对象,类似event,prop()方法设置或返回被选元素的属性和值。
scope.$apply(function () {
angular.forEach(scope.relateData, function (value) {
value.checked = isCheckd;
});
对于检查绑定的数据到底有没有发生变化,实际上是由scope.digest()完成的,但是我们几乎从来就没有直接调用过这个方法,而是调用scope.apply()方法,是因为在scope.apply()方法里面,它会去调用scope.digest()方法。scope.apply()方法带一个函数或者一个表达式,然后执行它,最后调用scope.digest()方法去更新bindings或者watchers。
// })
});
// $('.table').on('click', 'input.chkItem', function () {//checkbox .chkItem
// var uuid = $(this).attr('value');
// if ($(this).prop('checked')) {
// scope.$apply(function () {
// scope.$parent.include.push(uuid);
// _.pull(scope.$parent.exclude, uuid);
// scope.$emit('asset-check-stat');
// })
//
// } else {
// scope.$apply(function () {
// scope.$parent.exclude.push(uuid);
// _.pull(scope.$parent.include, uuid);
// scope.$emit('asset-check-stat');
// })
// }
//
// });
}
}
}
<div ng-controller="Aaa">
<div my-tab my-id="div1" my-name="name" my-fn="show(num)" class="J-tab"></div>
<div my-tab my-id="div2" my-name="name" my-fn="show(num)" class="J-tab"></div>
</div>
<script type="text/javascript">
var m1 = angular.module('myApp',[]);
m1.controller('Aaa',['$scope',function($scope){
$scope.name = 'xiecg';
$scope.age = 18;
$scope.show = function(num){
console.log(num);
};
}]);
m1.directive('myTab',function(){
return {
restrict : 'ECMA',
replace : true, //替换的方式插入内容//绑定策略
scope : {
myId : '@', //解析普通字符串
myName : '=', //解析数据
myFn : '&' //函数
},
controller : ['$scope',function($scope){
//共享数据存放在这里
$scope.name = 'this is a xiecg';
}],
template : '<div id="{{myId}}">\
<input type="button" value="1" class="active" ng-click="myFn({num:456})">\
<input type="button" value="2">\
<input type="button" value="3">\
<div style="display:block;">{{myName}}</div>\
<div>2222</div>\
<div>3333</div>\
</div>'
};
});
</script>
指令是:myTab
指令中定义的变量:myId myName myShow,在标签中写了数值之后可以在定义的指令中使用