指令是angularJs里非常常用和重要的一部分。
指令是什么:简单点说,指令就是一些附加在html元素上的自定义标记(例如:元素、属性、css类等),它告诉AngularJS的HTML编译器 ($compile) 在元素上附加某些指定的行为,甚至操作DOM、改变DOM元素,以及它的各级子节点。
angular 有一些内置的指令:ngBind,ngModel等,如<input ng-model="name">
指令创建
通常指令创建在独立的js文件作为一个模块,可以复用
页面
<body>
<hello></hello>
<div hello></div>
<div class="hello"></div>
<!--directive:hello -->
<div></div>
</body>
js文件
var snDirective = angular.module("snDirective",['ngCommon']);
/**
* 简单的例子
*/
snDirective.directive("hello", function(){
return {
restrict:'AEMC',
replace:true,
template:"<div> hello world</div>"
}
})
/**
* 图片加载失败时替换成指定图片
*/
snDirective.directive("errSrc", function() {
return {
link: function(scope, element, attrs) {
element.bind("error", function() {
//src属性 != errSrc属性。则src属性值设置为errSrc属性值
if (attrs.src != attrs["errSrc"]) {
attrs.$set("src", attrs["errSrc"]);
}
});
}
}
});
/**
* snDialog:弹出层窗口
*/
snDirective.directive("snDialog", function () {
return {
restrict: "AE",
replace: true,
transclude: true,
scope: {},
templateUrl: jsPath + "directive/sn-dialog.html?v=" + window.VERSION,
link : function(scope, element, attr) {
}
};
});
指令修改dom通常是在link函数中。link函数可以给指令元素绑定一些事件。如示例代码errSrc。指令里的link函数三、四个参数,element是元素,这里是指令本身,attrs是指令上的属性
restrict:匹配模式,即指令使用的方式。有A属性,E元素,M注释,C class。
什么情况下该用元素名,什么情况下该用属性名? 当创建一个含有自己模板的组件的时候,建议使用元素名,常见情况是,当你想为你的模板创建一个DSL(特定领域语言)的时候。如果仅仅想为已有的元素添加功能,建议使用属性名.
scope:{}:创建指令的独立作用域。如果页面多个相同指令,指令的template 如<input type="text" ng-model="userName">{{userName}}</input>
。修改其中一个指令的输入框,都会同时作用在其他几个相同的指令上。如果需要指令间互不影响则需要指令上添加scope:{} 配置项。
详细参考angularJs中文网指令文档。
transclude:指令内部是否可嵌套。即页面上指令内部与指令无关的html代码块可以嵌套到指令模板里的<div ng-transclude></div>
这里。
replace:将视图模板替换到自定义指令名称位置时,是否替换掉自定义指令名称,默认为false不替换。
指令与控制器
同一个controller里调用指令。
var myModule = angular.module("myModule",[]);
myModule.controller("myCtrl",["$scope", function($scope){
$scope.loadData = function(){
console.log("加载数据。。。。");
}
}])
myModule.directive("loader",function(){
return {
restrict: "AE",
link: function(scope,element,attr){
element.bind("mouseenter",function(){
scope.loadData();//因为指令在controller包含里,所以作用域一直,可以调用?
or
scope.$apply("loadData()");
})
}
}
})
<div ng-controller="myCtrl">
<loader>滑动加载</loader>
</div>
不同的控制器调用同一个指令。可以在指令上定义一个属性, 实现指令复用
var myModule = angular.module("myModule",[]);
myModule.controller("myCtrl",["$scope", function($scope){
$scope.loadData = function(){
console.log("加载数据。。。。");
}
}])
myModule.controller("myCtrl2",["$scope", function($scope){
$scope.loadData2 = function(){
console.log("加载数据。。。。222");
}
}])
myModule.directive("loader",function(){
return {
restrict: "AE",
link: function(scope,element,attr){
element.bind("mouseenter",function(){
scope.$apply(attr.howtoload());//howtoload不能驼峰
})
}
}
})
<div ng-controller="myCtrl">
<loader howToLoad="loadData()">滑动加载</loader>
</div>
<div ng-controller="myCtrl2">
<loader howToLoad="loadData2()">滑动加载</loader>
</div>
指令与指令交互
指令里的controller用于为指令暴露一组public方法,供外部指令调用。这是指令里controller的作用
var module = angular.module("myModule",[]);
module.directive("superman",function(){
return {
scope:{},
restrict: "AE",
controller: function(){//
$scope.abilities = [];
this.addStrength = function(){
$scope.abilities.push("strength");
}
this.addSpeed = function(){
$scope.abilities.push("speed");
}
}
link: function(scope,element,attr){
element.addClass("btn btn-primary");
element.bind("mouseenter",function(){
console.log(scope.abilities);
})
}
}
})
module.directive("strength",function(){
return {
require: "^superman",
link: function(scope,element,attrs, supermanCtrl){
supermanCtrl.addStrength();
}
}
})
module.directive("speed",function(){
return {
require: "^superman",
link: function(scope,element,attrs, supermanCtrl){
supermanCtrl.addSpeed();
}
}
})
<div class="row">
<div class="col-md-3">
<superman strength> 超人。。。力量</superman>
</div>
</div>
<div class="row">
<div class="col-md-3">
<superman strength speed> 超人。。。力量和速度</superman>
</div>
</div>
scope的绑定策略
@绑定
把当前的属性作为字符串传递。你还可以绑定来自外层的scope的值,在属性值中插入{{}}即可。
html代码,其中flavor是指令自定义属性,由于@绑定的字符串,所以flavor="{{ctrlFlavor}}"
里的ctrlFlavor只能是字符串,不能是对象
<div ng-controller="myCtrl">
<drink flavor="{{ctrlFlavor}}"></drink>
</div>
js代码
var myModule=angular.module("MyModule",[]);
myModule.controller('myCtrl',['$scope',function($scope){
$scope.ctrlFlavor="香菇";
}])
myModule.directive("drink",function(){
return{
restrict:'AE',
scope:{
flavor:'@'
},
template:"<div>{{zk}}</div>"
//link: function(scope,element,attrs){
// scope.flavor = attrs.flavor
//}
}
})
=绑定
与父scope中的属性进行双向绑定
html代码
<div ng-controller="myCtrl">
Ctrl:
<br>
<input type="text" ng-model="ctrlFlavor">
<br>
Directive:
<br>
<drink flavor="ctrlFlavor"></drink>
</div>
js代码
var myModule = angular.module("MyModule", []);
myModule.controller('myCtrl', ['$scope', function ($scope) {
$scope.ctrlFlavor = "香菇";
}]);
myModule.directive("drink", function () {
return {
restrict: 'AE',
scope: {
flavor: '='
},
template: '<input type="text" ng-model="flavor">'
}
});
注意
指令scope:{}里的flavor可以不和html里的flavor=”ctrlFlavor”的flavor相等。可以自命名为myflavor。
这时候就要scope:{myflavor: '=flavor'}
同时template里的ng-model="myflavor"
.
&绑定
传递来自父scope中的函数、稍后调用
html代码
<div ng-controller="MyCtrl">
<greeting greet="sayHello(name)"></greeting>
<greeting greet="sayHello(name)"></greeting>
<greeting greet="sayHello(name)"></greeting>
</div>
js代码
var myModule=angular.module("MyModule",[]);
myModule.controller('MyCtrl', ['$scope', function($scope){
$scope.sayHello=function(name){
alert("Hello "+name);
}
}])
myModule.directive("greeting", function() {
return {
restrict:'AE',
scope:{
greet:'&'
},
template:'<input type="text" ng-model="userName" /><br/>'
+ '<button class="btn btn-default" ng-click="greet({name:userName})">'
+ 'Greeting</button><br/>'
}
});