angular之directive小結


關於 restrict屬性

對於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

能夠混用,也能夠單獨使用。性能

對於scope屬性

@  @attr     本地做用域屬性
=  =attr     雙向屬性
&  &attr     父級做用域綁定

ps:ui

對於 & 父級做用域: 傳遞進來的參數必須是父級的函數方法,  而後在指令中,經過 test() 獲取到 傳遞進來的函數,這個還不夠,還必須再執行一次 test()() 纔是真正的執行這個方法。

或者在指令的調用上面,直接寫好test(t),而後在指令中調用的時候 ,$scope.test({t:'fda'}) 就能夠了。


對於 @ 本地做用域: 只能傳遞字符串進來,對於方法或者對象是傳遞不進來的

對於 = 雙向屬性: 能夠傳遞對象進來,也能夠是字符串,可是不能傳遞方法。  同時能夠在 指令中修改這個對象,父級裏面的這個對象也會跟着修改的。



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不兼容。

對於 compile (編譯)   link(連接),先編譯,後鏈接,可是有了編譯以後,對於連接就起不到到做用了。

在compile 階段主要是實現:標籤的解析和替換。 在編譯階段是獲取不到 scope 的。主要參數(element.attrbutes)

在link 階段主要是實現:數據綁定等操做。在link階段是能夠獲取到scope 的 主要參數是(scope,element,attrs);

link 與controller 的區別

對於一個指令,若是你想將當前指令的API暴露給其餘指令使用的時候,可使用controller,不然建議使用link。


對於require參數的理解

參數:字符串或者數組

? 若是在當前指令中沒有找到所需的控制器,就會將null傳遞給link函數中的第四個參數

^ 若是添加了這個前綴,指令會在上游的指令鏈中查找require參數所指定的控制器

?^ 合併了前面兩個說法

沒有前綴  指令就會自身提供的控制器中查找,若是沒有查找到,就會拋出異常來。

對於compile函數

返回一個對象或者函數。

與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函數來完成。

對於link 與scope

指令生成出的模板其實沒有太多的意義,除非他在特定的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節點。


關於改變指令的scope

默認狀況下,指令獲取他的父節點的controller的scope,但這並不適用全部狀況。若是將父controller的scope暴露給指令,那麼他們能夠隨意修改scope的屬性,在某些狀況下,你的指令但願可以添加一些僅限內部使用的屬性和方法,若是咱們在父的scope中添加,會污染父scope,其實咱們還能夠有兩個選擇。

  1. 一個子scope,這個scope原型繼承於父scope

  2. 一個隔離的scope,一個孤立存在不繼承父scope的scope

這樣的scope能夠經過指令對象中的scope屬性老配置

scope:true  // 建立了一個繼承父scope的新的子
scope:{}  // 建立了一個隔離的scope,隔離的scope在咱們想建立可重用的指令的時候是很是有好處的。
經過使用隔離的scope,咱們可以保證咱們的指令是自包含的,能夠被很容易的插入到HTML中,他內部不能訪問父的scope,因此保證了父scope不被污染。


transclude:'element' 和  transclude:true 的區別

有時候咱們要嵌入指令元素自己,而不只僅是他的內容,這種狀況下,咱們須要使用transclude:"element",和transclude:true不一樣,他講標記了ng-transclude指令的元素一塊兒包含到了指令模板中,使用transclusion, 你的link函數會獲取到一個叫transclude的連接函數,這個函數綁定了正確的指令scope,而且傳入了另一個擁有被嵌入dom元素拷貝的函數,你能夠在這個transclude函數中執行好比修改元素拷貝或者將他添加到dom上等操。


controller函數與require

若是你須要容許其餘指令和你的指令發生交互的話,你須要使用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);
    }
  };
});


關於replace參數

若是設置  repace : true 的話,就會隱藏掉 對於 指令命名的html 標籤

相似 <hello> </hello>  若是replace 設置爲true的話,就會消失不顯示。

關於transclude參數

若是設置了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);
            })
        }
    
    }
})


關於 require 參數

對於前綴 ?  ^     ?^   空

若是爲空的話,表示在當前指令中查找

若是爲?的話,表示沒有查找到的話,就會以null做爲link 函數的第四個參數

若是爲^ 的話,表示能夠指向上游查找指令。

關於require 引入多個指令,對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 共同存在的話,只會觸發compile 方法。而link 方法是不被觸發執行的。

而能夠經過這種方式:

{
 restrict:'EA',
 compile:function(element,attrs){
     // 編譯期間作的事情。
     
     return function link(scope,element,attrs,controller){
         // link  函數作的事情。
     }
     
 }

}
相關文章
相關標籤/搜索