angularjs directive 實例 詳解

前面提到了angularjs的factory,service,provider,這個可以理解成php的model,這種model是不帶html的,今天所說的directive,也可以理解成php的model,也可以理解成插件,只不過這種model是帶html的,例如:php的分頁函數。

一,angularjs directive的常用格式,以及參數說明

1,return

  1. var phonecatDirectives = angular.module('phonecatDirectives', []);  
  2.   
  3. phonecatDirectives.directive('directiveName'function($inject) {  
  4.   
  5.    return {  
  6.      template: '<div></div>',  
  7.   
  8.      replace: false,  
  9.   
  10.      transclude: true,  
  11.   
  12.      restrict: 'E',  
  13.   
  14.      scope: { ... },  
  15.   
  16.       controller: function($scope$element){ .... },     
  17.   
  18.       compile: function(tElement, tAttrs, transclude) {  
  19.        return {  
  20.          pre: function preLink(scope, iElement, iAttrs, controller) { ... },  
  21.          post: function postLink(scope, iElement, iAttrs, controller) { ... }  
  22.        }  
  23.      },  
  24.   
  25.      link: function(scope, iElement, iAttrs) { ... }  
  26.    };  
  27. });  

2,定義一個js的域

  1. var phonecatDirectives = angular.module('phonecatDirectives', []);  
  2.   
  3. phonecatDirectives.directive('directiveName'function($inject) {  
  4.   
  5.    var mydi = {  
  6.      template: '<div></div>',  
  7.       ..................... ,  
  8.      link: function(scope, iElement, iAttrs) { ... }  
  9.    };  
  10.   
  11.    return mydi;  
  12. });  

3,angularjs directive 對像參數說明

name - 當前scope的名稱,註冊時可以使用默認值(不填)。


priority(優先級)- 當有多個directive定義在同一個DOM元素時,有時需要明確它們的執行順序。這屬性用於在directive的compile function調用之前進行排序。如果優先級相同,則執行順序是不確定的(經初步試驗,優先級高的先執行,同級時按照類似棧的“後綁定先執行”。另外,測試時有點不小心,在定義directive的時候,兩次定義了一個相同名稱的directive,但執行結果發現,兩個compile或者link function都會執行)。


terminal(最後一組)- 如果設置爲”true”,則表示當前的priority將會成爲最後一組執行的directive。任何directive與當前的優先級相同的話,他們依然會執行,但順序是不確定的(雖然順序不確定,但基本上與priority的順序一致。當前優先級執行完畢後,更低優先級的將不會再執行)。


scope - 如果設置爲:

true - 將爲這個directive創建一個新的scope。如果在同一個元素中有多個directive需要新的scope的話,它還是隻會創建一個scope。新的作用域規則不適用於根模版(root of the template),因此根模版往往會獲得一個新的scope。

{}(object hash) - 將創建一個新的、獨立(isolate)的scope。”isolate” scope與一般的scope的區別在於它不是通過原型繼承於父scope的。這對於創建可複用的組件是很有幫助的,可以有效防止讀取或者修改父級scope的數據。這個獨立的scope會創建一個擁有一組來源於父scope的本地scope屬性(local scope properties)的object hash。這些local properties對於爲模版創建值的別名很有幫助(useful for aliasing values for templates -_-!)。本地的定義是對其來源的一組本地scope property的hash映射(Locals definition is a hash of local scope property to its source #&)$&@#)($&@#_):

@或@attr - 建立一個local scope property到DOM屬性的綁定。因爲屬性值總是String類型,所以這個值總是返回一個字符串。如果沒有通過@attr指定屬性名稱,那麼本地名稱將與DOM屬性的名稱一直。例如<widget my-attr=”hello {{name}}”>,widget的scope定義爲:{localName:’@myAttr’}。那麼,widget scope property的localName會映射出”hello {{name}}"轉換後的真實值。name屬性值改變後,widget scope的localName屬性也會相應地改變(僅僅單向,與下面的”=”不同)。name屬性是在父scope讀取的(不是組件scope)

=或=expression(這裏也許是attr) - 在本地scope屬性與parent scope屬性之間設置雙向的綁定。如果沒有指定attr名稱,那麼本地名稱將與屬性名稱一致。例如<widget my-attr=”parentModel”>,widget定義的scope爲:{localModel:’=myAttr’},那麼widget scope property “localName”將會映射父scope的“parentModel”。如果parentModel發生任何改變,localModel也會發生改變,反之亦然。(雙向綁定)

&或&attr - 提供一個在父scope上下文中執行一個表達式的途徑。如果沒有指定attr的名稱,那麼local name將與屬性名稱一致。例如<widget my-attr=”count = count + value”>,widget的scope定義爲:{localFn:’increment()’},那麼isolate scope property “localFn”會指向一個包裹着increment()表達式的function。一般來說,我們希望通過一個表達式,將數據從isolate scope傳到parent scope中。這可以通過傳送一個本地變量鍵值的映射到表達式的wrapper函數中來完成。例如,如果表達式是increment(amount),那麼我們可以通過localFn({amount:22})的方式調用localFn以指定amount的值(上面的例子真的沒看懂,&跑哪去了?)。


controller - controller 構造函數。controller會在pre-linking步驟之前進行初始化,並允許其他directive通過指定名稱的require進行共享(看下面的require屬性)。這將允許directive之間相互溝通,增強相互之間的行爲。controller默認注入了以下本地對象:

$scope - 與當前元素結合的scope

$element - 當前的元素

$attrs - 當前元素的屬性對象

$transclude - 一個預先綁定到當前轉置scope的轉置linking function :function(cloneLinkingFn)。(A transclude linking function pre-bound to the correct transclusion scope)


require - 請求另外的controller,傳入當前directive的linking function中。require需要傳入一個directive controller的名稱。如果找不到這個名稱對應的controller,那麼將會拋出一個error。名稱可以加入以下前綴:

? - 不要拋出異常。這使這個依賴變爲一個可選項。

^ - 允許查找父元素的controller


restrict - EACM的子集的字符串,它限制directive爲指定的聲明方式。如果省略的話,directive將僅僅允許通過屬性聲明:

E - 元素名稱: <my-directive></my-directive>

A - 屬性名: <div my-directive=”exp”></div>

C - class名: <div class=”my-directive:exp;”></div>

M - 註釋 : <!-- directive: my-directive exp -->


template - 如果replace 爲true,則將模版內容替換當前的HTML元素,並將原來元素的屬性、class一併遷移;如果爲false,則將模版元素當作當前元素的子元素處理。想了解更多的話,請查看“Creating Widgets”章節(在哪啊。。。Creating Components就有。。。)


templateUrl - 與template基本一致,但模版通過指定的url進行加載。因爲模版加載是異步的,所以compilation、linking都會暫停,等待加載完畢後再執行。


replace - 如果設置爲true,那麼模版將會替換當前元素,而不是作爲子元素添加到當前元素中。(注:爲true時,模版必須有一個根節點)


transclude - 編譯元素的內容,使它能夠被directive所用。需要(在模版中)配合ngTransclude使用(引用)。transclusion的優點是linking function能夠得到一個預先與當前scope綁定的transclusion function。一般地,建立一個widget,創建isolate scope,transclusion不是子級的,而是isolate scope的兄弟。這將使得widget擁有私有的狀態,transclusion會被綁定到父級(pre-isolate)scope中。(上面那段話沒看懂。但實際實驗中,如果通過<any my-directive>{{name}}</any my-directive>調用myDirective,而transclude設置爲true或者字符串且template中包含<sometag ng-transclude>的時候,將會將{{name}}的編譯結果插入到sometag的內容中。如果any的內容沒有被標籤包裹,那麼結果sometag中將會多了一個span。如果本來有其他東西包裹的話,將維持原狀。但如果transclude設置爲’element’的話,any的整體內容會出現在sometag中,且被p包裹)

true - 轉換這個directive的內容。(這個感覺上,是直接將內容編譯後搬入指定地方)

‘element’ - 轉換整個元素,包括其他優先級較低的directive。(像將整體內容編譯後,當作一個整體(外面再包裹p),插入到指定地方)


compile - 這裏是compile function,將在下面實例詳細講解


link - 這裏是link function ,將在下面實例詳細講解。這個屬性僅僅是在compile屬性沒有定義的情況下使用。


三,angularjs directive 實例講解

下面的實例都圍繞着,上面的參數來展開的

1,directive聲明方式實例

  1. //directive文件directives.js中定義一個myTest  
  2. 'use strict';  
  3.   
  4. var phonecatDirectives = angular.module('phonecatDirectives', []);  
  5.   
  6. phonecatDirectives.directive('myTest'function() {  
  7.     return {  
  8.         restrict: 'ACEM',  
  9.         require'^ngModel',  
  10.         scope: {  
  11.             ngModel: '='  
  12.         },  
  13.         template: '<div><h4>Weather for {{ngModel}}</h4></div>'  
  14.     }  
  15. });  
  16.   
  17. //controller文件controller.js中定義directive1  
  18. 'use strict';  
  19.   
  20. var dtControllers = angular.module('dtControllers', []);  
  21.   
  22. dtControllers.controller('directive1',['$scope',  
  23.     function($scope) {  
  24.         $scope.name = 'this is tank test';  
  25.     }  
  26. ]);  
  27.   
  28. //在app文件app.js中整合controller,directive  
  29.   
  30. 'use strict';  
  31.   
  32. var phonecatApp = angular.module('phonecatApp', [  
  33.     'phonecatDirectives',  
  34.     'dtControllers'  
  35. ]);  
  36.   
  37. //html文件  
  38. <script src="../lib/angular/angular.js"></script>  
  39. <script src="../js/app.js"></script>  
  40. <script src="../js/controller.js"></script>  
  41. <script src="../js/directives.js"></script>  
  42. <body ng-app="phonecatApp">  
  43.     <div ng-controller="directive1">  
  44.         <input type="text" ng-model="city" placeholder="Enter a city" />  
  45.   
  46.         <my-test ng-model="city" ></my-test>  
  47.         <span my-test="exp" ng-model="city"></span>  
  48.         <!-- directive: my-test exp -->  
  49.         <span ng-model="city"></span>  
  50.     </div>  
  51. </body>  

上例結果:<!-- directive: my-test exp -->這個不起作用,不知道爲什麼,嘗試了好多方法都不起作用。

2,template和templateUrl區別與聯繫

templateUrl其實根template功能是一樣的,只不過templateUrl加載一個html文件,上例中,我們也能發現問題,template後面根的是html的標籤,如果標籤很多呢,那就比較不爽了。可以將上例中的,template改一下。

  1. phonecatDirectives.directive('myTest'function() {  
  2.     return {  
  3.         restrict: 'ACEM',  
  4.         require'^ngModel',  
  5.         scope: {  
  6.             ngModel: '='  
  7.         },  
  8.         templateUrl:'../partials/tem1.html'   //tem1.html中的內容就是上例中template的內容。  
  9.     }  
  10. });  

3,scope重定義

  1. //directives.js中定義myAttr  
  2. phonecatDirectives.directive('myAttr'function() {  
  3.     return {  
  4.         restrict: 'E',  
  5.         scope: {  
  6.             customerInfo: '=info'  
  7.         },  
  8.         template: 'Name: {{customerInfo.name}} Address: {{customerInfo.address}}<br>' +  
  9.                   'Name: {{vojta.name}} Address: {{vojta.address}}'  
  10.     };  
  11. });  
  12.   
  13. //controller.js中定義attrtest  
  14. dtControllers.controller('attrtest',['$scope',  
  15.     function($scope) {  
  16.         $scope.naomi = { name: 'Naomi', address: '1600 Amphitheatre' };  
  17.         $scope.vojta = { name: 'Vojta', address: '3456 Somewhere Else' };  
  18.     }  
  19. ]);  
  20.   
  21. //html中  
  22. <body ng-app="phonecatApp">  
  23.     <div ng-controller="attrtest">  
  24.         <my-attr info="naomi"></my-attr>  
  25.     </div>  
  26. </body>  

運行結果:

  1. Name: Naomi Address: 1600 Amphitheatre      //有值,因爲customerInfo定義過的  
  2. Name: Address:       //沒值 ,因爲scope重定義後,vojta是沒有定義的  

可能把上面的directive簡單改一下,

  1. phonecatDirectives.directive('myAttr'function() {  
  2.     return {  
  3.         restrict: 'E',  
  4.         template: 'Name: {{customerInfo.name}} Address: {{customerInfo.address}}<br>' +  
  5.                   'Name: {{vojta.name}} Address: {{vojta.address}}'  
  6.     };  
  7. });  

運行結果如下:根上面正好相反

  1. Name: Address:  
  2. Name: Vojta Address: 3456 Somewhere Else  

4,transclude的使用

transclude的用法,有點像jquery裏面的$().html()功能

  1. //directives.js增加myEvent  
  2. phonecatDirectives.directive('myEvent'function() {  
  3.     return {  
  4.         restrict: 'E',  
  5.         transclude: true,  
  6.         scope: {  
  7.             'close''&onClick'     //根html中的on-click="hideDialog()"有關聯關係  
  8.         },  
  9.         templateUrl: '../partials/event_part.html'  
  10.     };  
  11. });  
  12.   
  13. //controller.js增加eventtest  
  14. dtControllers.controller('eventtest',['$scope','$timeout',  
  15.     function($scope$timeout) {  
  16.         $scope.name = 'Tobias';  
  17.         $scope.hideDialog = function () {  
  18.             $scope.dialogIsHidden = true;  
  19.             $timeout(function () {  
  20.                 $scope.dialogIsHidden = false;  
  21.             }, 2000);  
  22.         };  
  23.     }  
  24. ]);  
  25.   
  26. //event.html  
  27. <body ng-app="phonecatApp">  
  28.     <div ng-controller="eventtest">  
  29.         <my-event ng-hide="dialogIsHidden" on-click="hideDialog()">  
  30.             Check out the contents, {{name}}!  
  31.         </my-event>  
  32.     </div>  
  33. </body>  
  34.   
  35. //event_part.html  
  36. <div>  
  37.     <a href ng-click="close()">×</a>  
  38.     <div ng-transclude></div>  
  39. </div>  

5,controller,link,compile有什麼不同

  1. //directives.js增加exampleDirective  
  2. phonecatDirectives.directive('exampleDirective'function() {  
  3.     return {  
  4.         restrict: 'E',  
  5.         template: '<p>Hello {{number}}!</p>',  
  6.         controller: function($scope$element){  
  7.             $scope.number = $scope.number + "22222 ";  
  8.         },  
  9.         link: function(scope, el, attr) {  
  10.             scope.number = scope.number + "33333 ";  
  11.         },  
  12.         compile: function(element, attributes) {  
  13.             return {  
  14.                 pre: function preLink(scope, element, attributes) {  
  15.                     scope.number = scope.number + "44444 ";  
  16.                 },  
  17.                 post: function postLink(scope, element, attributes) {  
  18.                     scope.number = scope.number + "55555 ";  
  19.                 }  
  20.             };  
  21.         }  
  22.     }  
  23. });  
  24.   
  25. //controller.js添加  
  26. dtControllers.controller('directive2',['$scope',  
  27.     function($scope) {  
  28.         $scope.number = '1111 ';  
  29.     }  
  30. ]);  
  31.   
  32. //html  
  33. <body ng-app="phonecatApp">  
  34.     <div ng-controller="directive2">  
  35.         <example-directive></example-directive>  
  36.     </div>  
  37. </body>  

運行結果:

  1. Hello 1111 22222 44444 55555 !  

由結果可以看出來,controller先運行,compile後運行,link不運行。

將上例中的compile註釋掉

  1. //        compile: function(element, attributes) {  
  2. //            return {  
  3. //                pre: function preLink(scope, element, attributes) {  
  4. //                    scope.number = scope.number + "44444 ";  
  5. //                },  
  6. //                post: function postLink(scope, element, attributes) {  
  7. //                    scope.number = scope.number + "55555 ";  
  8. //                }  
  9. //            };  
  10. //        }  

運行結果:

  1. Hello 1111 22222 33333 !  

由結果可以看出來,controller先運行,link後運行,link和compile不兼容。

 



轉載請註明
作者:海底蒼鷹
地址:http://blog.51yip.com/jsjquery/1607.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章