深究AngularJS(4)——Directive和Scope數據隔離與交互


什麼是隔離 Scope

AngularJS 的 directive 默認能共享父 scope 中定義的屬性,例如在模版中直接使用父 scope 中的對象和屬性。通常使用這種直接共享的方式可以實現一些簡單的 directive 功能。當你需要創建一個可重複使用的 directive,只是偶爾需要訪問或者修改父 scope 的數據,就需要使用隔離 scope。當使用隔離 scope 的時候,directive 會創建一個沒有依賴父 scope 的 scope,並提供一些訪問父 scope 的方式。

爲什麼使用隔離 Scope

當你想要寫一個可重複使用的 directive,不能再依賴父 scope,這時候就需要使用隔離 scope 代替。共享 scope 可以直接共享父 scope,而隔離 scope 無法共享父scope。下圖解釋共享 scope 和隔離 scope 的區別:
圖片

示例可看:

共享 scope

使用共享 scope 的時候,可以直接從父 scope 中共享屬性。因此下面示例可以將那麼屬性的值輸出出來。使用的是父 scope 中定義的值。

js代碼:

app.controller("myController", function ($scope) {
  $scope.name = "hello world";
}).directive("shareDirective", function () {
  return {
    template: 'Say:`name`'
  }
});

html代碼

<div ng-controller="myController">
  <div share-directive=""></div>
</div>

輸出結果:

Say:hello world

隔離 scope

使用隔離 scope 的時候,無法從父 scope 中共享屬性。因此下面示例無法輸出父 scope 中定義的 name 屬性值。

js代碼:

app.controller("myController", function ($scope) {
  $scope.name = "hello world";
}).directive("isolatedDirective", function () {
  return {
    scope: {},
    template: 'Say:`name`'
  }
});

html代碼:

<div ng-controller="myController">
  <div isolated-directive=""></div>
</div>

輸出結果:

Say:

示例請點擊:http://kin-sample.coding.io/angular/directive/share-and-isolated-scope.html

從上圖可以看出共享 scope 允許從父 scope 滲入到 directive 中,而隔離 scope 不能,在隔離 scope 下,給 directive 創造了一堵牆,使得父 scope 無法滲入到 directive 中。

具體文檔可以參考:https://docs.angularjs.org/guide/directive#isolating-the-scope-of-a-directive

如何在 directive 中創建隔離 scope

在 Directive 中創建隔離 scope 很簡單,只需要定義一個 scope 屬性即可,這樣,這個 directive 的 scope 將會創建一個新的 scope,如果多個 directive 定義在同一個元素上,只會創建一個新的 scope。

angular.module('app').controller("myController", function ($scope) {
  $scope.user = {
    id:1,
    name:"hello world"
  };
}).directive('isolatedScope', function () {
  return {
    scope: {},
    template: 'Name: `user`.`name` Street: `user`.`addr`'
  };
});

現在 scope 是隔離的,user 對象將無法從父 scope 中訪問,因此,在 directive 渲染的時候 user 對象的佔位將不會輸出內容。

隔離 scope 和父 scope 如何交互

directive 在使用隔離 scope 的時候,提供了三種方法同隔離之外的地方交互。這三種分別是

  • @ 綁定一個局部 scope 屬性到當前 dom 節點的屬性值。結果總是一個字符串,因爲 dom 屬性是字符串。

  • & 提供一種方式執行一個表達式在父 scope 的上下文中。如果沒有指定 attr 名稱,則屬性名稱爲相同的本地名稱。

  • = 通過 directive 的 attr 屬性的值在局部 scope 的屬性和父 scope 屬性名之間建立雙向綁定。

@ 局部 scope 屬性

@ 方式局部屬性用來訪問 directive 外部環境定義的字符串值,主要是通過 directive 所在的標籤屬性綁定外部字符串值。這種綁定是單向的,即父 scope 的綁定變化,directive 中的 scope 的屬性會同步變化,而隔離 scope 中的綁定變化,父 scope 是不知道的。

如下示例:directive 聲明未隔離 scope 類型,並且使用@綁定 name 屬性,在 directive 中使用 name 屬性綁定父 scope 中的屬性。當改變父 scope 中屬性的值的時候,directive 會同步更新值,當改變 directive 的 scope 的屬性值時,父 scope 無法同步更新值。

js 代碼:

 app.controller("myController", function ($scope) {
   $scope.name = "hello world";
 }).directive("isolatedDirective", function () {
   return {
     scope: {
       name: "@"
     },
     template: 'Say:`name` <br>改變隔離scope的name:<input type="buttom" value="" ng-model="name" class="ng-pristine ng-valid">'
   }
 });

html 代碼:

<div ng-controller="myController">
   <div class="result">
     <div>
       父scope:<div>Say:`name`<br>改變父scope的name:<input type="text" value="" ng-model="name"/></div>
     </div>
     <div>
       隔離scope:<div isolated-directive name="`name`"></div>
     </div>
     <div>
       隔離scope(不使用`name`):<div isolated-directive name="name"></div>
     </div>
   </div>
</div>

具體演示請看:http://kin-sample.coding.io/angular/directive/isolated-scope-at-interact.html

= 局部 scope 屬性

= 通過 directive 的 attr 屬性的值在局部 scope 的屬性和父 scope 屬性名之間建立雙向綁定。
意思是,當你想要一個雙向綁定的屬性的時候,你可以使用=來引入外部屬性。無論是改變父 scope 還是隔離 scope 裏的屬性,父 scope 和隔離 scope 都會同時更新屬性值,因爲它們是雙向綁定的關係。

示例代碼:

js 代碼:

 app.controller("myController", function ($scope) {
   $scope.user = {
     name: 'hello',
     id: 1
   };
 }).directive("isolatedDirective", function () {
   return {
     scope: {
       user: "="
     },
     template: 'Say:`user`.`name` <br>改變隔離scope的name:<input type="buttom" value="" ng-model="user.name"/>'
   }
 });

html 代碼:

<div ng-controller="myController">
  <div>父scope:
    <div>
      Say:`user`.`name` <br> 改變父scope的name:<input type="text" value="" ng-model="user.name"/>
    </div>
  </div>
  <div>
    隔離scope:<div isolated-directive user="user"></div>
  </div>
  <div>
    隔離scope(使用`name`):<div isolated-directive user="`user`"></div>
  </div>
</div>

具體演示請看:http://kin-sample.coding.io/angular/directive/isolated-scope-eq-interact.html

& 局部 scope 屬性

& 方式提供一種途經是 directive 能在父 scope 的上下文中執行一個表達式。此表達式可以是一個 function。
比如當你寫了一個 directive,當用戶點擊按鈕時,directive 想要通知 controller,controller 無法知道 directive 中發生了什麼,也許你可以通過使用 angular 中的 event 廣播來做到,但是必須要在 controller 中增加一個事件監聽方法。
最好的方法就是讓 directive 可以通過一個父 scope 中的 function,當 directive 中有什麼動作需要更新到父 scope 中的時候,可以在父 scope 上下文中執行一段代碼或者一個函數。

如下示例在 directive 中執行父 scope 的 function。

js代碼:

 app.controller("myController", function ($scope) {
   $scope.value = "hello world";
   $scope.click = function () {
     $scope.value = Math.random();
   };
 }).directive("isolatedDirective", function () {
   return {
     scope: {
       action: "&"
     },
     template: '<input type="button" value="在directive中執行父scope定義的方法" ng-click="action()"/>'
   }
 });

html 代碼:

 <div  ng-controller="myController">
   <div>父scope:
     <div>Say:`value`</div>
   </div>
   <div>隔離scope:
     <div isolated-directive action="click()"></div>
   </div>
 </div>

具體演示請看:http://kin-sample.coding.io/angular/directive/isolated-scope-ad-interact.html

使用小結

在瞭解 directive 的隔離 scope 跟外部環境交互的三種方式之後,寫一些通用性的組件更加便捷和順手。不再擔心在 directive 中改變外部環境中的值,或者執行函數的重重困境了。
更多請參考API文檔:https://docs.angularjs.org/api/ng/service/$compile 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章