AngularJS指令的詳解

來源:互聯網
上載者:User

標籤:

  指令作為AngularJS中最為重要的部分,所以這個架構本身也是內建了比較多的的指令,但是在開發中,這些指令通常不能滿足我們的需要,所以我們也是需要自訂一些指令的。指令是我們用來擴充瀏覽器能力的技術之一。在DOM編譯期間,和HTML元素關聯著的指令會被檢測到,並且被執行。這使得指令可以為DOM指定行為,或者改變它。

  angular在編譯期間,編譯器會用$interpolate服務去檢查文本中是否嵌入了運算式。這個運算式會被當成一個監視器一樣註冊,並且作為$digest迴圈中的一部分,它會自動更新。

  HTML的編譯分為三個階段:

  1. 首先瀏覽器會用它的標準API將HTML解析成DOM。 你需要認清這一點,因為我們的模板必須是可被解析的HTML。這是AngularJS和那些“以字串為基礎而非以DOM元素為基礎的”模板系統的區別之處。

  2. DOM的編譯是由  $compile 方法來執行的。 這個方法會遍曆DOM並找到匹配的指令。一旦找到一個,它就會被加入一個指令列表中,這個列表是用來記錄所有和當前DOM相關的指令的。 一旦所有的指令都被確定了,會按照優先順序被排序,並且他們的  compile 方法會被調用。 指令的  $compile() 函數能修改DOM結構,並且要負責產生一個link函數(後面會提到)。$compile方法最後返回一個合并起來的連結函數,這時連結函數是每一個指令的compile函數返回的連結函數的集合。 

  3. 通過調用上一步所說的連結函數來將模板與範圍連結起來。這會輪流調用每一個指令的連結函數,讓每一個指令都能對DOM註冊監聽事件,和建立對範圍的的監聽。這樣最後就形成了範圍的DOM的動態綁定。任何一個範圍的改變都會在DOM上體現出來。

  指令的模板代碼:

 1 var myModule = angular.module(...); 2 myModule.directive(‘directiveName‘, function factory(injectables) { 3   var directiveDefinitionObject = { 4     priority: 0, 5     template: ‘<div></div>‘, 6     templateUrl: ‘directive.html‘, 7     replace: false, 8     transclude: false, 9     restrict: ‘A‘,10     scope: false,11     compile: function compile(tElement, tAttrs, transclude) {12       return {13         pre: function preLink(scope, iElement, iAttrs, controller) { ... },14         post: function postLink(scope, iElement, iAttrs, controller) { ... }15       }16     },17     link: function postLink(scope, iElement, iAttrs) { ... }18   };19   return directiveDefinitionObject;20 });

  大部分情況下你不需要控制這麼多細節,要簡化上面的代碼,我們首先需要依賴基本選項的預設值。如果使用預設值的話,上面的代碼可以簡化成:

1 var myModule = angular.module(...);2 myModule.directive(‘directiveName‘, function factory(injectables) {3   var directiveDefinitionObject = {4     compile: function compile(tElement, tAttrs) {5       return function postLink(scope, iElement, iAttrs) { ... }6     }7   };8   return directiveDefinitionObject;9 });

  由於大部分的指令只關心執行個體,並不需要將模板進行變形,所以我們還可以簡化成:

1 var myModule = angular.module(...);2 myModule.directive(‘directiveName‘, function factory(injectables) {3   return function postLink(scope, iElement, iAttrs) { ... }4 });

  上面代碼中的factory函數,我們叫工廠函數,它是用來建立指令的。它只會被調用一次:就是當編譯器第一次匹配到相應指令的時候,你可以在其中進行任何初始化的工作。調用它時使用的是  $injector.invoke , 所以它遵循所有注入器的規則。

  指令對象的屬性有一下:

  • 名稱name - 當前範圍的名稱 
  • 優先順序priority - 當一個DOM上有多個指令時,就會需要指定指令執行的順序。 這個優先順序就是用來在執行指令的compile函數前,先排序的。高優先順序的先執行。
  • terminal - 該參數用來定義是否停止當前元素上比本指令優先順序低的指令,如果值為true,就是正常情況,按照優先順序高低的順序來執行,如果設定為false,就不會執行當前元素上比本指令優先順序低的指令。
  • 範圍scope- 如果被定義成:
    • true - 那麼就會為當前指令建立一個新的範圍。如果有多個在同一個DOM上的指令要求建立新範圍,那麼只有一個新的會被建立。 這一建立新範圍的規則不適用於模板的根節點,因為模板的根節點總是會得到一個新的範圍。

    • {},對象雜湊 - 那麼一個新的“孤立的”範圍就會被建立。這個“孤立的”範圍區別於一般範圍的地方在於,它不會以原型繼承的方式直接繼承自父範圍。這對於建立可重用的組件是非常有用的,因為可重用的組件一般不應該讀或寫父範圍的資料。 這個“孤立的”範圍使用一個對象雜湊來表示,這個雜湊定義了一系列本地範圍屬性,這些屬性的值可以有以下幾種方式。
      • @ 或 @attr - 將本地範圍成員和DOM屬性綁定。使用@實現單向綁定。
      • = 或 =expression - 在本地範圍屬性和父範圍屬性間建立一個雙向的綁定。使用=實現雙向繫結。
      • & 或 &attr - 調用父scope裡的方法。
  • controller - 這個是指令內部的controller,跟angular中的controller不一樣。它的作用是暴露此指令的一些方法給其他指令使用。這個控制器函數是在先行編譯階段被執行的,並且它是共用的,這就使得指令間可以互相交流來擴大自己的能力。

  • require - 請求將另一個指令,假設為direct2,中的內部controller作為參數傳入到當前指令的連結函數link中,這樣在當前指令的link函數中,就可以調用direct2指令中的內部controller中定義的方法了。 這個請求需要傳遞被請求指令的名字。如果沒有找到,就會觸發一個錯誤。請求的名字可以加上下面兩個首碼:

      • ?  - 不要觸發錯誤,這隻是一個可選的請求。 
      • ^  - 沒找到的話,在父元素的範圍裡面去尋找有沒有。
  • restrict - EACM中的任意一個字母。它是用來限制指令的聲明格式的。如果沒有這一項。那就只允許使用屬性形式的指令。

    • E - 元素名稱:  <my-directive></my-directive>
    • A - 屬性:   <div my-directive="exp"> </div>
    • C - 類名:  <div class="my-directive: exp;"></div>
    • M - 注釋:   <!-- directive: my-directive exp -->
  • 模板template - 將當前的元素替換掉。 這個替換過程會自動將元素的屬性和css類名添加到新元素上。

  • 模板地址templateUrl - 和template屬性一樣,只不過這裡指示的是一個模板的URL。因為模板載入是非同步,所有編譯和連結都會等到載入完成後再執行。

  • 替換replace - 如果被設定成true,那麼頁面上指令內部裡面的內容會被模板替換。比如:<hello><div>這是指令內部的內容</div></hello>,hello指令內部的div內容將會被模板替換掉。

  • transclude -  如果不想讓指令內部的內容被模板替換,可以設定這個值為true。一般情況下需要和ngTransclude指令一起使用。 比如:template:"<div>hello every <div ng-transclude></div></div>",這時,指令內部的內容會嵌入到ng-transclude這個div中。也就是變成了<div>hello every <div>這是指令內部的內容</div></div>

  • 編譯compile - function compile(tElement, tAttrs, transclude) { ... }

    編譯函數是用來處理需要修改模板DOM的情況的。因為大部分指令都不需要修改模板,所以這個函數也不常用。需要用到的例子有  ngTrepeat ,這個是需要修改模板的,還有 ngView 這個是需要非同步載入內容的。編譯函數接受以下參數。 

    • tElement - template element - 指令所在的元素。對這個元素及其子項目進行變形之類的操作是安全的。

    • tAttrs - template attributes - 這個元素上所有指令聲明的屬性,這些屬性都是在編譯函數裡共用的。

    • transclude - 一個嵌入的連結函數  function(scope, cloneLinkingFn) 。 

    注意:在編譯函數裡面不要進行任何DOM變形之外的操作。 更重要的,DOM監聽事件的註冊應該在連結函數中做,而不是編譯函數中。

    編譯函數可以返回一個對象或者函數。

    • 返回函數 - 等效於在編譯函數不存在時,使用設定物件的  link 屬性註冊的連結函數。 

    • 返回對象 - 返回一個通過  pre 或  post 屬性註冊了函數的對象。

  • 連結link - function link(scope, iElement, iAttrs, controller) { ... }

    連結函數負責註冊DOM事件和更新DOM。它是在模板被複製之後執行的,它也是大部分指令邏輯代碼編寫的地方。

    • scope - 指令需要監聽的範圍。

    • iElement - instance element - 指令所在的元素。只有在  postLink 函數中對元素的子項目進行操作才是安全的,因為那時它們才已經全部連結好。 

    • iAttrs - instance attributes - 執行個體屬性,一個標準化的、所有聲明在當前元素上的屬性列表,這些屬性在所有連結函數間是共用的。

    • controller - 控制器執行個體,也就是當前指令通過require請求的指令direct2內部的controller。比如:direct2指令中的controller:function(){this.addStrength = function(){}},那麼,在當前指令的link函數中,你就可以通過controller.addStrength進行調用了。

    Pre-linking function 在子項目被連結前執行。不能用來進行DOM的變形,以防連結函數找不到正確的元素來連結。

    Post-linking function 所有元素都被連結後執行。

  當我們的angular應用引導啟動的時候,angular將會使用$compile服務遍曆DOM元素,在所有的指令都被識別之後,將會調用指令的compile方法,返回一個link函數,然後將這個link函數添加到稍後執行的 link 函數列表中,這個過程被稱為編譯階段。像ng-repeat這樣的指令,需要被重複複製很多次,compile函數只在編譯階段被執行一次,並且複製這些模板,但是link 函數會針對每個被複製的執行個體被執行。所以分開處理,讓我們在效能上有一定的提高。

參考文檔:http://www.tuicool.com/articles/fqiI73M

 

AngularJS指令的詳解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.