前面提到了angularjs的factory,service,provider,這個可以理解成php的model,這種model是不帶html的,今天所說的directive,也可以理解成php的model,也可以理解成插件,只不過這種model是帶html的,例如:php的分頁函數。
一,angularjs directive的常用格式,以及參數說明
1,return
- var phonecatDirectives = angular.module('phonecatDirectives', []);
- phonecatDirectives.directive('directiveName', function($inject) {
- return {
- template: '<div></div>',
- replace: false,
- transclude: true,
- restrict: 'E',
- scope: { ... },
- controller: function($scope, $element){ .... },
- compile: function(tElement, tAttrs, transclude) {
- return {
- pre: function preLink(scope, iElement, iAttrs, controller) { ... },
- post: function postLink(scope, iElement, iAttrs, controller) { ... }
- }
- },
- link: function(scope, iElement, iAttrs) { ... }
- };
- });
2,定義一個js的域
- var phonecatDirectives = angular.module('phonecatDirectives', []);
- phonecatDirectives.directive('directiveName', function($inject) {
- var mydi = {
- template: '<div></div>',
- ..................... ,
- link: function(scope, iElement, iAttrs) { ... }
- };
- return mydi;
- });
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聲明方式實例
- //directive文件directives.js中定義一個myTest
- 'use strict';
- var phonecatDirectives = angular.module('phonecatDirectives', []);
- phonecatDirectives.directive('myTest', function() {
- return {
- restrict: 'ACEM',
- require: '^ngModel',
- scope: {
- ngModel: '='
- },
- template: '<div><h4>Weather for {{ngModel}}</h4></div>'
- }
- });
- //controller文件controller.js中定義directive1
- 'use strict';
- var dtControllers = angular.module('dtControllers', []);
- dtControllers.controller('directive1',['$scope',
- function($scope) {
- $scope.name = 'this is tank test';
- }
- ]);
- //在app文件app.js中整合controller,directive
- 'use strict';
- var phonecatApp = angular.module('phonecatApp', [
- 'phonecatDirectives',
- 'dtControllers'
- ]);
- //html文件
- <script src="../lib/angular/angular.js"></script>
- <script src="../js/app.js"></script>
- <script src="../js/controller.js"></script>
- <script src="../js/directives.js"></script>
- <body ng-app="phonecatApp">
- <div ng-controller="directive1">
- <input type="text" ng-model="city" placeholder="Enter a city" />
- <my-test ng-model="city" ></my-test>
- <span my-test="exp" ng-model="city"></span>
- <!-- directive: my-test exp -->
- <span ng-model="city"></span>
- </div>
- </body>
上例結果:<!-- directive: my-test exp -->這個不起作用,不知道爲什麼,嘗試了好多方法都不起作用。
2,template和templateUrl區別與聯繫
templateUrl其實根template功能是一樣的,只不過templateUrl加載一個html文件,上例中,我們也能發現問題,template後面根的是html的標籤,如果標籤很多呢,那就比較不爽了。可以將上例中的,template改一下。
- phonecatDirectives.directive('myTest', function() {
- return {
- restrict: 'ACEM',
- require: '^ngModel',
- scope: {
- ngModel: '='
- },
- templateUrl:'../partials/tem1.html' //tem1.html中的內容就是上例中template的內容。
- }
- });
3,scope重定義
- //directives.js中定義myAttr
- phonecatDirectives.directive('myAttr', function() {
- return {
- restrict: 'E',
- scope: {
- customerInfo: '=info'
- },
- template: 'Name: {{customerInfo.name}} Address: {{customerInfo.address}}<br>' +
- 'Name: {{vojta.name}} Address: {{vojta.address}}'
- };
- });
- //controller.js中定義attrtest
- dtControllers.controller('attrtest',['$scope',
- function($scope) {
- $scope.naomi = { name: 'Naomi', address: '1600 Amphitheatre' };
- $scope.vojta = { name: 'Vojta', address: '3456 Somewhere Else' };
- }
- ]);
- //html中
- <body ng-app="phonecatApp">
- <div ng-controller="attrtest">
- <my-attr info="naomi"></my-attr>
- </div>
- </body>
運行結果:
- Name: Naomi Address: 1600 Amphitheatre //有值,因爲customerInfo定義過的
- Name: Address: //沒值 ,因爲scope重定義後,vojta是沒有定義的
可能把上面的directive簡單改一下,
- phonecatDirectives.directive('myAttr', function() {
- return {
- restrict: 'E',
- template: 'Name: {{customerInfo.name}} Address: {{customerInfo.address}}<br>' +
- 'Name: {{vojta.name}} Address: {{vojta.address}}'
- };
- });
運行結果如下:根上面正好相反
- Name: Address:
- Name: Vojta Address: 3456 Somewhere Else
4,transclude的使用
transclude的用法,有點像jquery裏面的$().html()功能
- //directives.js增加myEvent
- phonecatDirectives.directive('myEvent', function() {
- return {
- restrict: 'E',
- transclude: true,
- scope: {
- 'close': '&onClick' //根html中的on-click="hideDialog()"有關聯關係
- },
- templateUrl: '../partials/event_part.html'
- };
- });
- //controller.js增加eventtest
- dtControllers.controller('eventtest',['$scope','$timeout',
- function($scope, $timeout) {
- $scope.name = 'Tobias';
- $scope.hideDialog = function () {
- $scope.dialogIsHidden = true;
- $timeout(function () {
- $scope.dialogIsHidden = false;
- }, 2000);
- };
- }
- ]);
- //event.html
- <body ng-app="phonecatApp">
- <div ng-controller="eventtest">
- <my-event ng-hide="dialogIsHidden" on-click="hideDialog()">
- Check out the contents, {{name}}!
- </my-event>
- </div>
- </body>
- //event_part.html
- <div>
- <a href ng-click="close()">×</a>
- <div ng-transclude></div>
- </div>
5,controller,link,compile有什麼不同
- //directives.js增加exampleDirective
- phonecatDirectives.directive('exampleDirective', function() {
- return {
- restrict: 'E',
- template: '<p>Hello {{number}}!</p>',
- controller: function($scope, $element){
- $scope.number = $scope.number + "22222 ";
- },
- link: function(scope, el, attr) {
- scope.number = scope.number + "33333 ";
- },
- compile: function(element, attributes) {
- return {
- pre: function preLink(scope, element, attributes) {
- scope.number = scope.number + "44444 ";
- },
- post: function postLink(scope, element, attributes) {
- scope.number = scope.number + "55555 ";
- }
- };
- }
- }
- });
- //controller.js添加
- dtControllers.controller('directive2',['$scope',
- function($scope) {
- $scope.number = '1111 ';
- }
- ]);
- //html
- <body ng-app="phonecatApp">
- <div ng-controller="directive2">
- <example-directive></example-directive>
- </div>
- </body>
運行結果:
- Hello 1111 22222 44444 55555 !
由結果可以看出來,controller先運行,compile後運行,link不運行。
將上例中的compile註釋掉
- // compile: function(element, attributes) {
- // return {
- // pre: function preLink(scope, element, attributes) {
- // scope.number = scope.number + "44444 ";
- // },
- // post: function postLink(scope, element, attributes) {
- // scope.number = scope.number + "55555 ";
- // }
- // };
- // }
運行結果:
- Hello 1111 22222 33333 !
由結果可以看出來,controller先運行,link後運行,link和compile不兼容。
轉載請註明
作者:海底蒼鷹
地址:http://blog.51yip.com/jsjquery/1607.html