angular指令

轉自:http://www.cnblogs.com/rohelm/p/4051437.htmlhtml

 

對於指令,能夠把它簡單的理解成在特定DOM元素上運行的函數,指令能夠擴展這個元素的功能。express

首先來看個完整的參數示例再來詳細的介紹各個參數的做用及用法:數組

複製代碼
angular.module('myApp', []) 
.directive('myDirective', function() { 
    return { 
        restrict: String, 
        priority: Number, 
        terminal: Boolean, 
        template: String or Template Function: 
    function(tElement, tAttrs) {...}, 
    templateUrl: String, 
    replace: Boolean or String, 
    scope: Boolean or Object, 
    transclude: Boolean, 
    controller: String or 
    function(scope, element, attrs, transclude, otherInjectables) { ... }, 
    controllerAs: String, 
    require: String, 
    link: function(scope, iElement, iAttrs) { ... }, 
    compile: // 返回一個對象或鏈接函數,以下所示:
    function(tElement, tAttrs, transclude) { 
        return { 
            pre: function(scope, iElement, iAttrs, controller) { ... }, 
            post: function(scope, iElement, iAttrs, controller) { ... } 
           } 
        return function postLink(...) { ... } 
        } 
    }; 
 });
複製代碼

restrict[string]

restrict是一個可選的參數。用於指定該指令在DOM中以何種形式被聲明。默認值是A,即以屬性的形式來進行聲明。
可選值以下:
E(元素)瀏覽器

<my-directive></my-directive> 

A(屬性,默認值)緩存

<div my-directive="expression"></div> 

C(類名)安全

<div class="my-directive:expression;"></div> 

M(註釋)app

<--directive:my-directive expression-->

通常考慮到瀏覽器的兼容性,強烈建議使用默認的屬性就能夠即即以屬性的形式來進行聲明。最後一種方式建議再不要求逼格指數的時候千萬不要用。ide

Code:函數

複製代碼
 angular.module('app',[])
    .directive('myDirective', function () {
            return { 
                restrict: 'E', 
                template: '<a href="http://www.baidu.com">百度</a>' 
            };
        })
HtmlCode:
 <my-directive></my-directive>
複製代碼

 效果:post

priority[int]

大多數指令會忽略這個參數,使用默認值0,但也有些場景設置高優先級是很是重要甚至是必須的。例如,ngRepeat將這個參數設置爲1000,這樣就能夠保證在同一元素上,它老是在其餘指令以前被調用。

terminal[bool]

這個參數用來中止運行當前元素上比本指令優先級低的指令。但同當前指令優先級相同的指令仍是會被執行。
例如:ngIf的優先級略高於ngView(它們操控的實際就是terminal參數),若是ngIf的表達式值爲true,ngView就能夠被正常執行,但若是ngIf表達式的值爲false,因爲ngView的優先級較低就不會被執行。

template[string or function]

template參數是可選的,必須被設置爲如下兩種形式之一:

  •  一段HTML文本;
  • 一個能夠接受兩個參數的函數,參數爲tElement和tAttrs,並返回一個表明模板的字符串。tElement和tAttrs中的t表明template,是相對於instance的。

首先演示下第二種用法:

複製代碼
angular.module('app',[])
    .directive('myDirective', function () {
            return { 
                restrict: 'EAC', 
                template: function (elem, attr) {
                    return "<a href='" + attr.value + "'>" + attr.text + "</a>";
                }
        };
    })
複製代碼

HtmlCode:(效果同上,不作演示了)

<my-directive value="http://www.baidu.com" text="百度"></my-directive>
        <div my-directive
             value="http://www.baidu.com"
              text="百度"></div>

templateUrl[string or function]

templateUrl是可選的參數,能夠是如下類型:

  • 一個表明外部HTML文件路徑的字符串;
  • 一個能夠接受兩個參數的函數,參數爲tElement和tAttrs,並返回一個外部HTML文件路徑的字符串。

不管哪一種方式,模板的URL都將經過ng內置的安全層,特別是$getTrustedResourceUrl,這樣能夠保護模板不會被不信任的源加載。 默認狀況下,調用指令時會在後臺經過Ajax來請求HTML模板文件。加載大量的模板將嚴重拖慢一個客戶端應用的速度。爲了不延遲,能夠在部署應用以前對HTML模板進行緩存。

Code:

複製代碼
    angular.module('app',[])
    .directive('myDirective', function () {
            return { 
                restrict: 'AEC', 
                templateUrl: function (elem, attr) {
                    return attr.value + ".html";  //固然這裏咱們能夠直接指定路徑,同時在模板中能夠包含表達式
                }
        };
    })
複製代碼

replace[bool]

replace是一個可選參數,若是設置了這個參數,值必須爲true,由於默認值爲false。默認值意味着模板會被看成子元素插入到調用此指令的元素內部,
例如上面的示例默認值狀況下,生成的html代碼以下:

<my-directive value="http://www.baidu.com" text="百度"><a href="http://www.baidu.com">百度</a></my-directive>

若是設置replace=true

<a href="http://www.baidu.com" value="http://www.baidu.com" text="百度">百度</a>

據我觀察,這種效果只有設置restrict="E"的狀況下,纔會表現出實際效果。

介紹完基本的指令參數後,就要涉及到更重要的做用域參數了...

scope參數[bool or object]

 scope參數是可選的,能夠被設置爲true或一個對象。默認值是false。

若是一個元素上有多個指令使用了隔離做用域,其中只有一個能夠生效。只有指令模板中的根元素能夠得到一個新的做用域。所以,對於這些對象來講scope默認被設置爲true。內置指令ng-controller的做用,就是從父級做用域繼承並建立一個新的子做用域。它會建立一個新的從父做用域繼承而來的子做用域。這裏的繼承就不在贅述,和麪向對象中的繼承基本是一直的。

 首先咱們來分析一段代碼:

複製代碼
       <div ng-app="app" ng-init="name= '祖父'">
            <div ng-init="name='父親'">
                第一代:{{ name }}
                <div ng-init="name= '兒子'" ng-controller="SomeController">
                    第二代: {{ name }}
                    <div ng-init="name='孫子'">
                        第三代: {{ name }}
                    </div>
                </div>
            </div>
        </div> 
複製代碼

咱們發現第一代,咱們初始化name爲父親,可是第二代和第三代實際上是一個做用域,那麼他們的name實際上是一個對象,所以出現的效果以下:

第一代:父親
第二代: 孫子
第三代: 孫子

咱們在修改一下代碼,把第三代隔離開來再看看效果:

複製代碼
 <div ng-app="app"ng-init="name= '祖父'">
            <div ng-init="name='父親'">
                第一代:{{ name }}
                <div ng-init="name= '兒子'" ng-controller="SomeController">
                    第二代: {{ name }}
                    <div ng-init="name='孫子'" ng-controller="SecondController">
                        第三代: {{ name }}
                    </div>
                </div>
            </div>
        </div>
複製代碼

JsCode:

複製代碼
 angular.module('app', [])
        .controller('SomeController',function($scope) {
            
        })
       .controller('SecondController', function ($scope) {
        
    }) 
複製代碼

效果以下:

第一代:父親
第二代: 兒子
第三代: 孫子

在修改下代碼來看看繼承:

複製代碼
       <div ng-app="app"ng-init="name= '祖父的吻'">
            <div>
                第一代:{{ name }}
                <div ng-controller="SomeController">
                    第二代: {{ name }}
                    <div  ng-controller="SecondController">
                        第三代: {{ name }}
                    </div>
                </div>
            </div>
        </div> 
複製代碼

 

效果以下:

第一代:祖父的吻
第二代: 祖父的吻
第三代: 祖父的吻

若是要建立一個可以從外部原型繼承做用域的指令,將scope屬性設置爲true,簡單來講就是可繼承的隔離,即不能反向影響父做用域。

 再來看個例子:

複製代碼
    angular.module('myApp', [])
        .controller('MainController', function ($scope) {
        })
        .directive('myDirective', function () {
            return {
                restrict: 'A',
                scope:false,//切換爲{},true測試
                priority: 100,
                template: '<div>內部:{{ myProperty }}<input ng-model="myProperty"/></div>'
            };
        });
複製代碼

Html代碼:

 <div ng-controller='MainController' ng-init="myProperty='Hello World!'">
        外部: {{ myProperty}}
        <input ng-model="myProperty" />
        <div my-directive></div>
    </div>

 當咱們改變scope的值咱們會發現

false:繼承但不隔離

true:繼承並隔離

{}:隔離且不繼承 

 transclude

transclude是一個可選的參數。默認值是false。嵌入一般用來建立可複用的組件,典型的例子是模態對話框或導航欄。咱們能夠將整個模板,包括其中的指令經過嵌入所有傳入一個指令中。指令的內部能夠訪問外部指令的做用域,而且模板也能夠訪問外部的做用域對象。爲了將做用域傳遞進去,scope參數的值必須經過{}或true設置成隔離做用域。若是沒有設置scope參數,那麼指令內部的做用域將被設置爲傳入模板的做用域。

只有當你但願建立一個能夠包含任意內容的指令時,才使用transclude: true。

 咱們來看兩個例子-導航欄:

複製代碼
    <div side-box title="TagCloud">
        <div class="tagcloud">
            <a href="">Graphics</a>
            <a href="">ng</a>
            <a href="">D3</a>
            <a href="">Front-end</a>
            <a href="">Startup</a>
        </div>
   </div>
複製代碼

JsCode:

複製代碼
 angular.module('myApp', []) 
 .directive('sideBox', function() { 
     return { 
         restrict: 'EA', 
         scope: { 
             title: '@' 
         }, 
         transclude: true, 
         template: '<div class="sidebox"><div class="content"><h2 class="header">' +
             '{{ title }}</h2><span class="content" ng-transclude></span></div></div>' 
         }; 
    }); 
複製代碼

這段代碼告訴ng編譯器,將它從DOM元素中獲取的內容放到它發現ng-transclude指令的地方。

再來你看個官網的例子:

複製代碼
angular.module('docsIsoFnBindExample', [])
  .controller('Controller', ['$scope', '$timeout', function($scope, $timeout) {
    $scope.name = 'Tobias';
    $scope.hideDialog = function () {
      $scope.dialogIsHidden = true;
      $timeout(function () {
        $scope.dialogIsHidden = false;
      }, 2000);
    };
  }])
  .directive('myDialog', function() {
    return {
      restrict: 'E',
      transclude: true,
      scope: {
        'close': '&onClose'
      },
      templateUrl: 'my-dialog-close.html'
    };
  });
複製代碼
my-dialog-close.html
<div class="alert">
  <a href class="close" ng-click="close()">&times;</a>
  <div ng-transclude></div>
</div>

index.html

<div ng-controller="Controller">
  <my-dialog ng-hide="dialogIsHidden" on-close="hideDialog()">
    Check out the contents, {{name}}!
  </my-dialog>
</div>

若是指令使用了transclude參數,那麼在控制器沒法正常監聽數據模型的變化了。建議在連接函數裏使用$watch服務。

 controller[string or function]

 controller參數能夠是一個字符串或一個函數。當設置爲字符串時,會以字符串的值爲名字,來查找註冊在應用中的控制器的構造函數.

angular.module('myApp', []) 
.directive('myDirective', function() { 
restrict: 'A',  
controller: 'SomeController' 
}) 

能夠在指令內部經過匿名構造函數的方式來定義一個內聯的控制器

複製代碼
angular.module('myApp',[]) 
.directive('myDirective', function() { 
restrict: 'A', 
controller: 
function($scope, $element, $attrs, $transclude) { 
// 控制器邏輯放在這裏
} 
}); 
複製代碼

咱們能夠將任意能夠被注入的ng服務注入到控制器中,即可以在指令中使用它了。控制器中也有一些特殊的服務能夠被注入到指令當中。這些服務有:

1. $scope

與指令元素相關聯的當前做用域。
2. $element
當前指令對應的元素。
3. $attrs
由當前元素的屬性組成的對象。 

<div id="aDiv"class="box"></div>
具備以下的屬性對象:
{ 
id: "aDiv", 
class: "box" 
} 

4. $transclude
嵌入連接函數會與對應的嵌入做用域進行預綁定。transclude連接函數是實際被執行用來克隆元素和操做DOM的函數。

複製代碼
  angular.module('myApp',[])
 .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.text(clone.text());
                 $element.append(a);
             });
         }
     };
 });
複製代碼

html

    <my-link value="http://www.baidu.com">百度</my-link>
    <div my-link value="http://www.google.com">谷歌</div>

僅在compile參數中使用transcludeFn是推薦的作法。link函數能夠將指令互相隔離開來,而controller則定義可複用的行爲。若是咱們但願將當前指令的API暴露給其餘指令使用,可使用controller參數,不然可使用link來構造當前指令元素的功能性(即內部功能)。若是咱們使用了scope.$watch()或者想要與DOM元素作實時的交互,使用連接會是更好的選擇。使用了嵌入,控制器中的做用域所反映的做用域可能與咱們所指望的不同,這種狀況下,$scope對象沒法保證能夠被正常更新。當想要同當前屏幕上的做用域交互時,可使用傳入到link函數中的scope參數。

controllerAs[string]

controllerAs參數用來設置控制器的別名,這樣就能夠在視圖中引用控制器甚至無需注入$scope。

<div ng-controller="MainController as main">
        <input type="text" ng-model="main.name" />
        <span>{{ main.name }}</span>
    </div> 

JsCode:

  angular.module('myApp',[])
   .controller('MainController', function () {
       this.name = "Halower";
   });

控制器的別名使路由和指令具備建立匿名控制器的強大能力。這種能力能夠將動態的對象建立成爲控制器,而且這個對象是隔離的、易於測試。

 require[string or string[]]

 require爲字符串表明另一個指令的名字。require會將控制器注入到其所指定的指令中,並做爲當前指令的連接函數的第四個參數。字符串或數組元素的值是會在當前指令的做用域中使用的指令名稱。在任何狀況下,ng編譯器在查找子控制器時都會參考當前指令的模板。

  • 若是不使用^前綴,指令只會在自身的元素上查找控制器。指令定義只會查找定義在指令做當前用域中的ng-model=""
  • 若是使用?前綴,在當前指令中沒有找到所須要的控制器,會將null做爲傳給link函數的第四個參數。
  • 若是添加了^前綴,指令會在上游的指令鏈中查找require參數所指定的控制器。
  •  若是添加了?^ 將前面兩個選項的行爲組合起來,咱們可選擇地加載須要的指令並在父指令鏈中進行查找
  • 若是沒有任何前綴,指令將會在自身所提供的控制器中進行查找,若是沒有找到任何控制器(或具備指定名字的指令)就拋出一個錯誤

compile【object or function】

compile選項自己並不會被頻繁使用,可是link函數則會被常用。本質上,當咱們設置了link選項,其實是建立了一個postLink() 連接函數,以便compile() 函數能夠定義連接函數。一般狀況下,若是設置了compile函數,說明咱們但願在指令和實時數據被放到DOM中以前進行DOM操做,在這個函數中進行諸如添加和刪除節點等DOM操做是安全的。

compile和link選項是互斥的。若是同時設置了這兩個選項,那麼會把compile所返回的函數看成連接函數,而link選項自己則會被忽略。

編譯函數負責對模板DOM進行轉換。連接函數負責將做用域和DOM進行連接。 在做用域同DOM連接以前能夠手動操做DOM。在實踐中,編寫自定義指令時這種操做是很是罕見的,但有幾個內置指令提供了這樣的功能。 

link

compile: function(tEle, tAttrs, transcludeFn) {
 //todo:
 return function(scope, ele, attrs) {
 // 連接函數
 };

連接函數是可選的。若是定義了編譯函數,它會返回連接函數,所以當兩個函數都定義時,編譯函數會重載連接函數。若是咱們的指令很簡單,而且不須要額外的設置,能夠從工廠函數(回調函數)返回一個函數來代替對象。若是這樣作了,這個函數就是連接函數。

ngModel

它提供更底層的API來處理控制器內的數據,這個API用來處理數據綁定、驗證、 CSS更新等不實際操做DOM的事情,ngModel 控制器會隨 ngModel 被一直注入到指令中,其中包含了一些方法。爲了訪問ngModelController必須使用require設置.

ngModelController經常使用的元素以下:

  •  1.爲了設置做用域中的視圖值,須要調用 ngModel.$setViewValue() 函數。

$setViewValue() 方法適合於在自定義指令中監聽自定義事件(好比使用具備回調函數的jQuery插件),咱們會但願在回調時設置$viewValue並執行digest循環。

複製代碼
複製代碼
 angular.module('myApp')
        .directive('myDirective', function() {
            return {
                require: '?ngModel',
                link: function(scope, ele, attrs, ngModel) {
                    if (!ngModel) return;
                    $(function() {
                        ele.datepicker({
//回調函數 onSelect: function(date) { // 設置視圖和調用 apply scope.$apply(function() { ngModel.$setViewValue(date); }); } }); }); } }; });
複製代碼
複製代碼
      • 2.$render方法能夠定義視圖具體的渲染方式
      • 3.屬性
        1. $viewValue
        $viewValue屬性保存着更新視圖所需的實際字符串。
        2. $modelValue
        $modelValue由數據模型持有。 $modelValue和$viewValue多是不一樣的,取決於$parser流水線是否對其進行了操做。
        3. $parsers
        $parsers 的值是一個由函數組成的數組,其中的函數會以流水線的形式被逐一調用。ngModel 從DOM中讀取的值會被傳入$parsers中的函數,並依次被其中的解析器處理。
        4. $formatters
        $formatters的值是一個由函數組成的數組,其中的函數會以流水線的形式在數據模型的值發生變化時被逐一調用。它和$parser流水線互不影響,用來對值進行格式化和轉換,以便在綁定了這個值的控件中顯示。
        5. $viewChangeListeners
        $viewChangeListeners的值是一個由函數組成的數組,其中的函數會以流水線的形式在視圖中的值發生變化時被逐一調用。經過$viewChangeListeners,能夠在無需使用$watch的狀況下實現相似的行爲。因爲返回值會被忽略,所以這些函數不須要返回值。
        6. $error
        $error對象中保存着沒有經過驗證的驗證器名稱以及對應的錯誤信息。
        7. $pristine
        $pristine的值是布爾型的,能夠告訴咱們用戶是否對控件進行了修改。
        8. $dirty
        $dirty的值和$pristine相反,能夠告訴咱們用戶是否和控件進行過交互。
        9. $valid
        $valid值能夠告訴咱們當前的控件中是否有錯誤。當有錯誤時值爲false, 沒有錯誤時值爲true。
        10. $invalid$invalid值能夠告訴咱們當前控件中是否存在至少一個錯誤,它的值和$valid相反。
相關文章
相關標籤/搜索