本篇讲解指令的scope属性:
scope属性值可以有三种:
一.scope:false
默认值,这种情况下,指令的作用域就是指令元素当前所在的作用域.
二.scope:true
创建一个继承了父作用域的子作用域,这样,指令可以访问到父作用域里的值,父作用域的属性值一旦被修改,子作用域里相应的属性值也会被修改,但是子作用域里的属性值修改,不会影响到父作用域里的属性值
举个栗子:
html:
<!DOCTYPE html> <html ng-app="dirAppModule"> <head> <title>20.7.4 指令-scope</title> <meta charset="utf-8"> <script src="../angular.js"></script> <script type="text/ng-template" id="text.html"> <div> <h3 style="background-color:{{color}}" ng-transclude></h3> </div> </script> <script src="script.js"></script> </head> <body> <div ng-controller="bgColor"> <p>父作用域的color值:{{color}}</p> <input ng-model="color" placeholder="请输入颜色值"/> <br/> <cd-hello><span>code_bunny</span></cd-hello> </div> </body> </html>
js:
/*20.7.4 指令 */ var appModule = angular.module('dirAppModule', []); appModule.controller('bgColor', function ($scope) { }); appModule.directive('cdHello', function () { return { restrict: 'EAC', templateUrl: 'text.html', replace: true, transclude: 'element', scope: true, link: function (scope, ele, attrs, ctrl, trans) { ele.bind('click', function () { scope.$apply(function () { scope.color = '#C0DCC0' }) }); ele.bind('mouseover', function () { ele.css({'cursor': 'pointer'}) }); } } });
创建一个这样的应用:输入颜色值可以改变指令元素的背景色,点击指令元素,重置颜色值为豆沙绿
→点击元素后
可以看到,输入颜色值,父作用域里的color值改变,指令的scope里的color值也会改变,但是指令的scope里的color值改变,不会影响到父元素的color值.这就是scope为true时指令的作用域.
三.scope:{}
scope属性为一个json对象,这种情况下,为指令创建一个独立的作用域.这个作用域和父作用域没有任何关系.
注意,不能够在这个对象中自定义属性和值,比如scope:{name:'code_bunny'},想象中这样定义就是给指令的独立作用域中定义了一个name属性,值为'code_bunny',但这样是不对的!这个json对象中,只能使用三种绑定策略.如果需要给这个独立作用域添加某个属性,应该在在link函数的scope参数下进行添加.
当这个独立的scope需要和父scope进行通信时,可以使用三种绑定策略:
(一)@绑定
@绑定能让独立作用域访问到父作用域里绑定的属性值,但是独立作用域下的这个值被修改,不影响到父作用域.类似于scope:true,但是仅仅是绑定的属性,而不是全部的属性.
来个栗子:
html:
<!DOCTYPE html> <html ng-app="dirAppModule"> <head> <title>20.7(1)指令-scope</title> <meta charset="utf-8"> <script src="../angular.js"></script> <script type="text/ng-template" id="text.html"> <div> <h3 style="background-color:{{color}}" ng-transclude></h3> </div> </script> <script src="script.js"></script> </head> <body> <div ng-controller="bgColor"> <input ng-model="color" placeholder="请输入颜色值"/> <br/> <cd-hello col-attr="{{color}}"><span>code_bunny</span></cd-hello> </div> </body> </html>
js:
/*20.7.1 指令 */ var appModule = angular.module('dirAppModule', []); appModule.controller('bgColor',function($scope){}); appModule.directive('cdHello',function(){ return { restrict:'EAC', templateUrl:'text.html', replace:true, transclude:'element', scope:{ color:'@colAttr' }, link:function(scope,ele,attrs,ctrl,trans){ ele.bind('click',function(){ scope.$apply(function(){ scope.color = '#C0DCC0'; }) }); ele.bind('mouseover',function(){ ele.css({'cursor':'pointer'}) }); } } });
→输入pink→点击元素
可以看到,独立作用域绑定父元素的color属性后,父元素的color属性修改,指令里的color属性也被修改了.但是独立作用域下的color属性被修改,不会影响到父元素.
注意在这段代码里,有这3个颜色:
1.color: 这个是父元素里的color属性名
2.col-attr: 这个是指令元素里用于绑定而创建的一个元素的属性名
3.color: 这个color是独立作用域里的一个属性名
以上三个属性名都是可以自己取的,不需要保持一致.绑定的方法直接看代码里的颜色.
为了看得更清楚,我把它单独拎出来写一下:
父作用域有一个属性叫color: <input ng-model="color" placeholder="请输入颜色值"/>
指令元素创建一个col-attr属性,让它等于"{{color}}" <cd-hello col-attr="{{color}}"><span>code_bunny</span></cd-hello>
指令的scope里进行绑定:
scope:{
color:'@colAttr'
}
然后在link函数里就可以使用scope.color属性了.
有两个需要注意的地方:
1.元素的属性不能使用驼峰命名,因为html不能识别大小写,只能使用'-',在js绑定时@后面改成驼峰命名.
2.当2和3同名时,可以简写,比如:
属性名叫mycolor:<cd-hello mycolor="{{color}}"><span>code_bunny</span></cd-hello>
scope下的属性名也叫mycolor: scope:{mycolor:'@mycolor'}
这种情况下可以简写成: scope:{mycolor:'@'}
(二)=绑定:
=绑定能够让独立作用域和父作用域之间的某个属性完全共享,无论是父作用域下这个属性被修改还是独立作用域下这个属性被修改,另一个作用域下的这个属性都会同步变化.
来个栗子:
<!DOCTYPE html> <html ng-app="dirAppModule"> <head> <title>20.7(2)指令-scope</title> <meta charset="utf-8"> <script src="../angular.js"></script> <script type="text/ng-template" id="text.html"> <div> <h3 style="color:{{text_color}};background-color:{{color}}" ng-transclude></h3> </div> </script> <script src="script.js"></script> </head> <body> <div ng-controller="bgColor"> <input ng-model="color" placeholder="请输入颜色值"/> <br/> <cd-hello bg-color="color"><span>code_bunny</span></cd-hello> </div> </body> </html>
js:
/*20.7.2 指令 */ var appModule = angular.module('dirAppModule', []); appModule.controller('bgColor',function($scope){}); appModule.directive('cdHello',function(){ return { restrict:'EAC', templateUrl:'text.html', replace:true, transclude:'element', scope:{ color:'=bgColor' }, link:function(scope,ele,attrs,ctrl,trans){ ele.bind('click',function(){ scope.$apply(function(){ scope.color = '#C0DCC0' }) }); ele.bind('mouseover',function(){ ele.css({'cursor':'pointer'}) }); } } });
→输入pink→点击元素
可以看到,和@绑定不同,当我点击元素,改变了独立作用域下的color属性时,父作用域下的color属性也被改变了.他们是完全同步的.
和@绑定一样.同样有三个颜色,同样2和3同名的时候可以简写.这里就不再赘述了.
需要特别注意的一点是:@绑定是col-attr="{{color}}",而=绑定是bg-color="color".一个是"{{color}}",一个是"color".这个千万不能混淆了
(三)&绑定:
&绑定使得独立作用域可以访问父作用域里的函数.
来个栗子:
html:
<!DOCTYPE html> <html ng-app="dirAppModule"> <head> <title>20.7(3)指令-scope</title> <meta charset="utf-8"> <script src="../angular.min.js"></script> <script type="text/ng-template" id="text.html"> <div> <h3 ng-transclude></h3> </div> </script> <script src="script.js"></script> </head> <body> <div ng-controller="sayHelloCode"> <hello sayhello="sayHello(name)"><span>code_bunny</span></hello> </div> </body> </html>
js:
/*20.7.3 指令 */ var appModule = angular.module('dirAppModule', []); appModule.controller('sayHelloCode',function($scope){ $scope.sayHello=function(a){alert('hello,'+a)} }); appModule.directive('hello',function(){ return { restrict:'EAC', replace:true, templateUrl:'text.html', transclude:'element', scope:{ sayHello:'&sayhello' }, link:function(scope,ele,attrs,ctrl,trans){ ele.bind('click',function(){ scope.sayHello({name:'code_bunny'}); }); ele.bind('mouseover',function(){ ele.css({'cursor':'pointer'}) }); } } });
当点击指令元素的时候,执行sayHello()方法.这里需要注意参数的传入方法:
sayhello中有一个形参:
$scope.sayHello=function(a){alert('hello,'+a)}
在html中定义传入的参数名字叫name
<hello sayhello="sayHello(name)"><span>code_bunny</span></hello>
在调用的时候传入一个对象{name:'code_bunny'}:
scope.sayHello({name:'code_bunny'});
这样,就可以把'code_bunny'作为a的实参传入.
和上面两种绑定一样.同样有三个颜色,同样2和3同名的时候可以简写.这里就不再赘述了.
需要注意的是,&绑定的时候,sayhello="sayHello()"绑定的方法是需要()的.
三种绑定方法就介绍完了,还有很重要的注意点:
在使用绑定策略的时候,都是通过指令元素的属性来绑定的,需要注意的是,用作绑定的这个属性名千万不要和指令名本身相同,这有可能会造成错误,比如这样:
<color color="{{mycolor}}"><color/>
指令的名字叫color, 用于绑定mycolor属性值的属性名也叫color,这样就不太好.需要避免这种情况的发生.
最后,这三种绑定策略是可以用在同一个指令中的.比如下面这个栗子:
html:
<!DOCTYPE html> <html ng-app="dirAppModule"> <head> <title>20.7(5)指令-scope</title> <meta charset="utf-8"> <script src="../angular.js"></script> <script type="text/ng-template" id="text.html"> <div> <h3 style="color:{{textColor}};background-color:{{bgColor}}" ng-transclude></h3> </div> </script> <script src="script.js"></script> </head> <body> <div ng-controller="bgColor"> <input ng-model="bg_color" placeholder="请输入颜色值"/> <input ng-model="text_color" placeholder="请输入颜色值"/> <br/> <cd-hello col-attr="{{bg_color}}" text-color="text_color" say-hello="sayHello()"><span>code_bunny</span></cd-hello> </div> </body> </html>
js:
/*20.7.5 指令 */ var appModule = angular.module('dirAppModule', []); appModule.controller('bgColor', function ($scope) { $scope.sayHello=function(){alert('hello')} }); appModule.directive('cdHello', function () { return { restrict: 'EAC', templateUrl: 'text.html', replace: true, transclude: 'element', scope: { bgColor: '@colAttr', textColor: '=textColor', sayHello: '&' }, link: function (scope, ele, attrs, ctrl, trans) { ele.bind('click', function () { scope.$apply(function () { scope.sayHello(); scope.color = '#C0DCC0'; scope.textColor = '#ccc'; }) }); ele.bind('mouseover', function () { ele.css({'cursor': 'pointer'}) }); } } });
→输入背景色为pink,文字色为green→点击元素弹出hello后:
背景色使用@绑定,文字色使用=绑定,sayHello函数使用&绑定.所以,一个指令中可以混合使用多个多种绑定策略.
完整代码:https://github.com/OOP-Code-Bunny/angular/tree/master/OREILLY 20.7.1 指令.html - 20.7.5 指令 .html
https://github.com/OOP-Code-Bunny/angular/blob/master/OREILLY/script.js