對於angular 指令的理解:html
好比你想建立一個指令 想被調用的人經過
jquery
<my-directive></my-direvtive>
的話,對於屬性就能夠設置爲 restrict : E(元素)express
若是是
數組
<div my-directive> </div>
restrict : A(屬性,默認值)app
若是是:
dom
<div class=「directive:expression;」> </div>
restrict : C(類名)函數
<-- directive:my-directive expression -->
restrict : M(註釋)post
能夠混用,也能夠單獨使用。性能
@ @attr 本地做用域屬性 = =attr 雙向屬性 & &attr 父級做用域綁定
ps:ui
對於 & 父級做用域: 傳遞進來的參數必須是父級的函數方法, 而後在指令中,經過 test() 獲取到 傳遞進來的函數,這個還不夠,還必須再執行一次 test()() 纔是真正的執行這個方法。
或者在指令的調用上面,直接寫好test(t),而後在指令中調用的時候 ,$scope.test({t:'fda'}) 就能夠了。
對於 @ 本地做用域: 只能傳遞字符串進來,對於方法或者對象是傳遞不進來的。
對於 = 雙向屬性: 能夠傳遞對象進來,也能夠是字符串,可是不能傳遞方法。 同時能夠在 指令中修改這個對象,父級裏面的這個對象也會跟着修改的。
//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不兼容。
對於 compile (編譯) link(連接),先編譯,後鏈接,可是有了編譯以後,對於連接就起不到到做用了。
在compile 階段主要是實現:標籤的解析和替換。 在編譯階段是獲取不到 scope 的。主要參數(element.attrbutes)
在link 階段主要是實現:數據綁定等操做。在link階段是能夠獲取到scope 的 主要參數是(scope,element,attrs);
對於一個指令,若是你想將當前指令的API暴露給其餘指令使用的時候,可使用controller,不然建議使用link。
參數:字符串或者數組
? 若是在當前指令中沒有找到所需的控制器,就會將null傳遞給link函數中的第四個參數
^ 若是添加了這個前綴,指令會在上游的指令鏈中查找require參數所指定的控制器
?^ 合併了前面兩個說法
沒有前綴 指令就會自身提供的控制器中查找,若是沒有查找到,就會拋出異常來。
返回一個對象或者函數。
與link 是互斥的,優先級高於 link 。
能夠理解成:compile函數在link函數被執行以前用來作一些DOM改造的。
若是有了compile函數,就不能有link 函數了,link函數是由compile函數返回的。
要注意的是 compile 是不能訪問scope的,而且返回一link函數。
compile:function(tElem,attrs){ // tElem:指令所在的元素 // attrs: 元素上賦予的參數的標準化列表 // 在這邊能夠作一些對於dom元素的操做 return function(scope,elem,attrs){ } }
因此,大多數狀況下,你只須要link 函數,由於大部分的指令只須要考慮註冊事件的監聽,監聽模型,以及更新DOM等,這些都是能夠在link函數中完成的,可是對於像ng-repeat之類的指令,須要克隆和重複dom元素屢次,在link函數執行以前由compile函數來完成。
指令生成出的模板其實沒有太多的意義,除非他在特定的scope下編譯,默認狀況下,指令並不會建立新的子scope
,更多的,他是使用父scope,也就是說,若是指令存在於一個controller下,他就會使用controller的scope,如何運行
scope,咱們須要用到一個link函數,他由指令定義對象中的link屬性配置。
link:function(scope,elem,attrs){ // scope:父親controller的scope // elem:jqLite(jquery的子集)包裝的dom元素,不須要再使用$()包裝了。 // attrs:一個包含了指令所在元素的屬性的標準化的參數對象, // 例子:好比你在html中添加一些屬性,那麼能夠在link函數中經過attrs.someAttribute來使用他。 }
因此說:link 函數主要是爲dom 元素添加事件監聽,監聽模型屬性變化,以及更新dom。
另外 若是 有參數 require 的話,對於link 函數方面就會多一個參數 controller
{ require:'?ngModal', link:function(scope,element,attrs,ctrl){ // 這裏 ctrl 就是 require 進來的ctrl } }
若是require的參數是數組的話。
{ require:['?ngModal','?test'], link:function(scope,element,attrs,ctrls){ // 這裏 ctrl 就是 require 進來的ctrl var modalCtrl = ctrls[0]; var testCtrl = ctrls[1]; } }
在應用引導啓動的時候,ng開始使用$compile服務遍歷dom元素,這個服務基於註冊過的指令在標記文本中搜索指令,一旦全部的指令被識別後,ng執行他們的compile方法,正如前面所講的,compile 方法返回一個link函數,被添加到稍後執行的link函數列表中,這個階段被稱爲編譯階段。若是指令須要被克隆屢次,好比ng-repeat,compile函數只會在編譯階段被執行一次,複製這些模板,可是link函數會針對於每一個被複制的實例被執行。因此分開來處理,讓咱們在性能方面有必定的提高。
這也說明了爲何在compile函數中不能訪問scope對象。在編譯階段之後,就開始了連接階段,在這個階段,全部的link函數被一一執行。指令創造出來的模板會在正確的scope下被解析和處理。而後返回具備事件響應的真實的dom節點。
默認狀況下,指令獲取他的父節點的controller的scope,但這並不適用全部狀況。若是將父controller的scope暴露給指令,那麼他們能夠隨意修改scope的屬性,在某些狀況下,你的指令但願可以添加一些僅限內部使用的屬性和方法,若是咱們在父的scope中添加,會污染父scope,其實咱們還能夠有兩個選擇。
一個子scope,這個scope原型繼承於父scope
一個隔離的scope,一個孤立存在不繼承父scope的scope
這樣的scope能夠經過指令對象中的scope屬性老配置
scope:true // 建立了一個繼承父scope的新的子
scope:{} // 建立了一個隔離的scope,隔離的scope在咱們想建立可重用的指令的時候是很是有好處的。 經過使用隔離的scope,咱們可以保證咱們的指令是自包含的,能夠被很容易的插入到HTML中,他內部不能訪問父的scope,因此保證了父scope不被污染。
有時候咱們要嵌入指令元素自己,而不只僅是他的內容,這種狀況下,咱們須要使用transclude:"element",和transclude:true不一樣,他講標記了ng-transclude指令的元素一塊兒包含到了指令模板中,使用transclusion, 你的link函數會獲取到一個叫transclude的連接函數,這個函數綁定了正確的指令scope,而且傳入了另一個擁有被嵌入dom元素拷貝的函數,你能夠在這個transclude函數中執行好比修改元素拷貝或者將他添加到dom上等操。
若是你須要容許其餘指令和你的指令發生交互的話,你須要使用controller函數,好比有些狀況下,你須要經過組合兩個指令來實現一個ui組件,那麼你能夠經過以下使用
app.directive('outerDirective', function() { return { scope: {}, restrict: 'AE', controller: function($scope, $compile, $http) { // $scope is the appropriate scope for the directive this.addChild = function(nestedDirective) { // this refers to the controller console.log('Got the message from nested directive:' + nestedDirective.message); }; } }; });
當另一個指令須要使用到這個controller的時候
app.directive('innerDirective', function() { return { scope: {}, restrict: 'AE', require: '^outerDirective', // require controller 方法 // link 參數中就會多一個參數 就是那個require 進來的controller link: function(scope, elem, attrs, controllerInstance) { //the fourth argument is the controller instance you require scope.message = "Hi, Parent directive"; controllerInstance.addChild(scope); } }; });
若是設置 repace : true 的話,就會隱藏掉 對於 指令命名的html 標籤
相似 <hello> </hello> 若是replace 設置爲true的話,就會消失不顯示。
若是設置了transclude 爲true的話,就會把本來指令標籤中用於寫的東西放置到 ng-transclude 中去。
<div ng-transclude> 方式獲取到的內容</div>
若是設置了transclude 爲true的話,除了可使用ng-transclude 指令, 若是你還須要對本來的內容進行替換的話
能夠在link 或者controller裏面添加一個參數$transclude
link:function($scope,$element,$attrs,controller,$transclude){ // clone 參數就是用戶輸入進去的內容。 $transclude(function(clone){ // 進行其餘操做。 }); }
案例
// html <div my-link value=" target="_blank">百度</div> // js var app = angular.module('app',[]); app.directive('myLink',function(){ return { restrict:'EA', transclude:true, controller:function($scope,$element,$attrs,$transclude){ $transclude(function(clone){ var a = angular.element('<a>'); a.attr('href',$attrs.value); a.attr('target',$attrs.target); a.text(clone.text()); $element.append(a); }) } } })
對於前綴 ? ^ ?^ 空
若是爲空的話,表示在當前指令中查找
若是爲?的話,表示沒有查找到的話,就會以null做爲link 函數的第四個參數
若是爲^ 的話,表示能夠指向上游查找指令。
若是
require:['?^add','?^minor']
的話,
會致使 link 方法影響
link:function(scope,element,attrs,resultCtrl){ // add : resultCtrl[0]; // minor: resultCtrl[1]; }
若是想調用指令的方法,須要在對應指令中的controller 中定義方法
app.directive('add',function(){ return { controller:function(){ this.add = function(){ } } } })
則調用的時候就須要
resultCtrl[0].add() 就能夠調用了。
因爲 compile 和link 共同存在的話,只會觸發compile 方法。而link 方法是不被觸發執行的。
而能夠經過這種方式:
{ restrict:'EA', compile:function(element,attrs){ // 編譯期間作的事情。 return function link(scope,element,attrs,controller){ // link 函數作的事情。 } } }