angular學習筆記(三十)-指令(8)-scope

詩&遠方發表於2014-09-25

本篇講解指令的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.當23同名時,可以簡寫,比如:

   屬性名叫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屬性也被改變了.他們是完全同步的.

和@繫結一樣.同樣有三個顏色,同樣23同名的時候可以簡寫.這裡就不再贅述了.

需要特別注意的一點是:@繫結是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的實參傳入.

和上面兩種繫結一樣.同樣有三個顏色,同樣23同名的時候可以簡寫.這裡就不再贅述了.

需要注意的是,&繫結的時候,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

相關文章