AngularJS 講解,四 Directive

來源:互聯網
上載者:User

標籤:

AngularJS  Directive 自訂指令(我最喜歡AngularJs的功能之一)

一:什麼時候我們會用到directive

    1.使html更具語義化,不用深入瞭解研究代碼的邏輯便可知道大致邏輯。

  2.抽象出一個自訂群組件,可以重複使用。

二:directive的定義及其使用方法

    1.下面是一個directive參數詳細模板

angular.module(‘app‘,[]);//申明一個調用angularjs塊   angular.module(‘app‘).directive(‘directiveName‘, function factory() {    var directiveDefinitionObject = {    priority: 0, 
   restrict:‘A‘,   template: ‘<div></div>‘,   templateUrl: ‘directive.html‘,   replace: false,   transclude: false,   scope: false,   compile: function compile(tElement, tAttrs, transclude) {     return {       pre: function preLink(scope, iElement, iAttrs, controller) { ... },       post: function postLink(scope, iElement, iAttrs, controller) { ... }     }   },   link: function postLink(scope, iElement, iAttrs) { ... } }; return directiveDefinitionObject; });

  2.參數詳解

       priority:

    (數字),選擇性參數,指明指令的優先順序,若在單個DOM上有多個指令,則優先順序高的先執行;

   terminal:

    (布爾型),選擇性參數,值為true或false,若設定為true,則優先順序低於此指令的其他指令則無效,不會被調用(優先順序相同的還是會執行);

      restrict:

          (字串)選擇性參數,指明指令在DOM裡面以什麼形式被聲明;

    取值有:E(元素),A(屬性),C(類),M(注釋),其中預設值為A;當然也可以兩個一起用,比如EA.表示即可以是元素也可以是屬性。

    E(元素):<directiveName></directiveName>  
    A(屬性):<div directiveName=‘expression‘></div>  
    C(類): <div class=‘directiveName‘></div>  
    M(注釋):<--directive:directiveName expression-->  
    一般情況下E/A/C用得比較多。

  template:

    (字串或函數),選擇性參數

    例:(1)字串時:  

<!DOCTYPE html> <html lang="zh" ng-app="app"> <head>  <meta charset="UTF-8">  <title>AngularJS Directive</title>  <script type="text/javascript" src="angular.min.js"></script> </head> <body> <hello-world></hello-world> </body> <script type="text/javascript"> angular.module(‘app‘, []); angular.module.(‘app‘).directive(‘helloWorld‘, function() {  return {  restrict: ‘E‘,  template: ‘<div><h1>Hi I am hello world.</h1></div>‘,  replace: true  }; }); </script> </html> 

   (2)函數時:有兩個參數tElement和tAttrs

      tElement:使用此指令的元素

        tAttrs:該指令元素上的屬性

<!DOCTYPE html> <html lang="zh" ng-app="app"> <head>  <meta charset="UTF-8">  <title>AngularJS Directive</title>  <script type="text/javascript" src="angular.min.js"></script> </head> <body> <hello-world></hello-world> <hello-world2 title = ‘I am a Hello World 2.‘></hello-world2> </body> <script type="text/javascript"> angular.module(‘app‘, []); app.directive(‘helloWorld‘, function() {  return {  restrict: ‘E‘,  template: ‘<div><h1>Hi I am a Hello Worl.</h1></div>‘,  replace: true  }; }); app.directive("helloWorld2",function(){  return{  restrict:‘EAC‘,  template: function(tElement,tAttrs){  var _html = ‘‘;  _html += ‘<div>‘+tAttrs.title+‘</div>‘;  return _html;  }  };  }); </script> </html> 

  templateUrl:

    (字串或者函數)選擇性參數

    字串:代表HTML檔案路徑的字串

    函數:可接收兩個參數tElement和tAttrs(大致同上)

    (PS:由於載入html模板是通過非同步載入的,若載入大量的模板會拖慢網站的速度,所以我們可以先緩衝模板)

    例:(把要載入的頁面 先載入好 包含在你需要的html裡)    

<!DOCTYPE html> <html lang="zh" ng-app="app"> <head>  <meta charset="UTF-8">  <title>AngularJS Directive</title>  <script type="text/javascript" src="angular.min.js"></script> </head> <body> <hello-world></hello-world> </body> <script type="text/javascript"> angular.module(‘app‘, []); angular.module("app").directive(‘helloWorld‘, function() {  return {  restrict: ‘E‘,  templateUrl: ‘hello.html‘,  replace: true  }; }); </script> <script type=‘text/ng-template‘ id=‘hello.html‘>  <div><h1>Hi I am Hello world.</h1></div> </script> </html> 

 還有一種方法:

angular.module("app").run(["$templateCache", function($templateCache) {  $templateCache.put("hello.html",  "<div><h1>Hi I am Hello world.</h1></div>"); }]); 

  replace:

    (布爾值):預設值是false. true:替換掉指令即(<hello-world></hello-world>),false:不替換

  transclude:(是否想要指令內部的內容被模板替換掉)

    (布爾值):預設值是false. true:需要和ng transclude一起使用

    例:template:"<div>hello every <div ng-transclude></div></div>"

        這時,指令內部的內容會嵌入到ng-transclude這個div中。也就是變成了<div>hello every <div>這是指令內部的內容</div></div>。

  scope:

    1)預設值false。表示繼承父範圍;(繼承不隔離)

    2)true。表示繼承父範圍,並建立自己的範圍(子範圍);(繼承隔離)

    3){}。表示建立一個全新的隔離範圍;(不繼承隔離)

    (PS:當你想要建立一個可重用的組件時隔離範圍是一個很好的選擇,通過隔離範圍我們確保指令是‘獨立‘的,並可以輕鬆地插入到任何HTML app中,並且這種做法防止了父範圍被汙染;)

    下面針對隔離範圍進行詳細講解:

       a.隔離範圍怎樣去訪問父範圍:

       Directive 在使用隔離 scope 的時候,提供了三種方法同隔離之外的地方互動.

      1). @ 

        (用來訪問 directive 外部環境定義的字串值,主要是通過 directive 所在的標籤屬性綁定外部字串值。這種綁定是單向的,即父 scope 的綁定變化,directive 中的 scope 的屬性會同步變化,                                     而隔離 scope 中的綁定變化,父 scope 是不知道的。)PS:相當於繼承隔離

        scope:{

        name:"@"

        }     

      2). &

        (& 方式提供一種途經是 directive 能在父 scope 的上下文中執行一個運算式。當 directive 中有什麼動作需要更新到父 scope 中的時候,可以在父 scope 上下文中執行一段代碼或者一個函數。PS:即綁定的是方法)

        

<!DOCTYPE html> <html lang="zh" ng-app="app"> <head>  <meta charset="UTF-8">  <title>AngularJS Directive</title>  <script type="text/javascript" src="angular.min.js"></script> </head> <body>  <div ng-controller="myController">  <div>父scope:  <div>Say:{{value}}</div>  </div>  <div>隔離scope:  <div isolated-directive action="click()"></div>  </div> </div> </body> <script type="text/javascript"> angular.module(‘app‘, []); app.controller("myController", function ($scope) {  $scope.value = "hello world";  $scope.click = function () {  $scope.value = Math.random();  };  }).directive("isolatedDirective", function () {  return {  scope: {  action: "&"  },  template: ‘<input type="button" value="在directive中執行父scope定義的方法" ng-click="action()"/>‘  }  }) </script> </html> 

 

      3). =

       (通過 directive 的 attr 屬性的值在局部 scope 的屬性和父 scope 屬性名稱之間建立雙向繫結。
        意思是,當你想要一個雙向繫結的屬性的時候,你可以使用=來引入外部屬性。無論是改變父 scope 還是隔離 scope 裡的屬性,父 scope 和隔離 scope 都會同時更新屬性值,因為它們是雙向繫結的關係。)

      例:

<!DOCTYPE html> <html lang="zh" ng-app="app"> <head>  <meta charset="UTF-8">  <title>AngularJS Directive</title>  <script type="text/javascript" src="angular.min.js"></script> </head> <body> <div ng-controller="myController">  <div>父scope:  <div>Say:{{user.name}}<br>改變父scope的name:<input type="text" value="" ng-model="userBase.name"/></div>  </div>  <div>隔離scope:  <div isolated-directive user="userBase"></div>  </div> </div> </body> <script type="text/javascript"> angular.module(‘app‘, []); angular.module.("app").controller("myController", function ($scope) {  $scope.userBase = {  name: ‘hello‘,  id: 1  };  }).directive("isolatedDirective", function () {  return {  scope: {  user: "="  },  template: ‘Say:{{user.name}} <br>改變隔離scope的name:<input type="buttom" value="" ng-model="user.name"/>‘  }  }) </script> </html> 

   controller:

    (可以是一個字串或者函數)

    

angular.module(‘app‘, []) angular.module.("app").directive(‘myDirective‘, function() { restrict: ‘A‘, controller: ‘DefinitionController‘ }) // 應用中其他的地方,可以是同一個檔案或被index.html包含的另一個檔案 angular.module(‘app‘) .controller(‘DefinitionController‘, function($scope, $element, $a也可以直接在指令內部的定義為匿名函數,同樣我們可以再這裡注入任何服務($log,$timeout等等) js:angular.module(‘app‘,[]) .directive(‘myDirective‘, function() { restrict: ‘A‘, controller: function($scope, $element, $attrs, $transclude) { // 控制器邏輯放在這裡 } }); 

另外還有一些特殊的服務(參數)可以注入

(1)$scope,與指令元素相關聯的範圍

(2)$element,當前指令對應的 元素

(3)$attrs,由當前元素的屬性群組成的對象

(4)$transclude,嵌入連結函數,實際被執行用來複製元素和操作DOM的函數

注意: 除非是用來定義一些可複用的行為,一般不推薦在這使用。
         指令的控制器和link函數(後面會講)可以進行互換。區別在於,控制器主要是用來提供可在指令間複用的行為但link連結函數只能在當前內部指令中定義行為,且無法再指令間複用。

   

<!DOCTYPE html> <html lang="zh" ng-app="app"> <head>  <meta charset="UTF-8">  <title>AngularJS入門學習</title>  <script type="text/javascript" src="angular.min.js"></script> </head>  <hello mycolor ="red">I am Hello World.</hello> </body> <script type="text/javascript"> angular.module(‘app‘, []); angular.module("app").directive(‘hello‘, function() {  return {   restrict: ‘EA‘,   transclude: true, //注意此處必須設定為true   controller:   function ($scope, $element,$attrs,$transclude,$log) { //在這裡你可以注入你想注入的服務   $transclude(function (clone) {    var a = angular.element(‘<p>‘);    a.css(‘color‘, $attrs.mycolor);    a.text(clone.text());    $element.append(a);   });   $log.info("hello everyone");   }  };  }); </script> </html> 

   這裡如果我們想要實用的父範圍:$scope.$parent

                               新的範圍:$scope.$parent.new()

  controllerAs 

    設定控制器的別名(angular1.2給我們帶來的新的文法糖)

           例:

<script>  angular.module(‘app‘,[]).directive(‘myDirective‘, function () {  return {   restrict: ‘EA‘,   transclude: true,   controller:‘someController‘,   controllerAs:‘mainController‘  //..其他配置  };  });  </script> 

   require

    字串或數組

      字串代表另一個指令的名字,作為link函數的第四個參數。假設現在我們要編寫兩個指令,兩個指令中的link連結函數中存在有很多重合的方法,這時候我們就可以將這些重複的方法寫在第三個指令的controller中(上面也講到controller經常用來提供指令間的複用行為)然後在這兩個指令中,require這個擁有controller欄位的的指令(第三個指令),最後通過link連結函數的第四個參數就可以引用這些重合的方法了。

    例

<!doctype html> <html ng-app="app"> <head>  <script src="angular.min.js"></script> </head> <body>    <outer-directive>  <inner-directive></inner-directive>  <inner-directive2></inner-directive2>  </outer-directive>  <script>  angular.module(‘app‘, []);  angular.module("app").directive(‘outerDirective‘, function() {   return {   scope: {},   restrict: ‘AE‘,   controller: function($scope) {    this.say = function(someDirective) {    console.log(‘Show:‘ + someDirective.message);    };   }   };  });  angular.module("app").directive(‘innerDirective‘, function() {   return {   scope: {},   restrict: ‘AE‘,   require: ‘^outerDirective‘,   link: function(scope, elem, attrs, controllerInstance) {    scope.message = "Hi,I am Ruby.";    controllerInstance.say(scope);   }   };  });  app.directive(‘innerDirective2‘, function() {   return {   scope: {},   restrict: ‘AE‘,   require: ‘^outerDirective‘,   link: function(scope, elem, attrs, controllerInstance) {    scope.message = "Hi,I am Hello World.";    controllerInstance.say(scope);   }   };  });      </script>   </body> </html> 

     require參數有四種:   

      1)沒有首碼,指令會在自身提供的控制器中進行尋找,如果找不到任何控制器,則會拋出一個error

      2)?如果在當前的指令沒有找到所需的控制器,則會將null傳給link串連函數的第四個參數

      3)^如果在當前的指令沒有找到所需的控制器,則會尋找父元素的控制器

      4)?^組合

  compile function

    function compile(tElement, tAttrs, transclude) { ... }

    編譯函數用來修改模板dom的(不常用)

    需要用到編譯函數例如:ngTrepeat;ngView(需要非同步載入內容的)。

    各參數意義:

    tElement - template element 該指令所在的元素。

      tAttrs - template attributes 指令元素上所聲明的屬性。

    transclude - 一個嵌入的連結函數function(scope, cloneLinkingFn)。

    注意:在編譯函數裡面不要進行任何DOM變形之外的操作。 更重要的,DOM監聽事件的註冊應該在連結函數中做,而不是編譯函數中。 編譯函數可以返回一個對象或者函數。 返回函數 - 等效於在編譯函數不存在時,使用設定物件的link屬性註冊的連結函數。 返回對象 - 返回一個通過pre或post屬性註冊了函數的對象。參考下面pre-linking和post-liking函數的解釋。

  link function

    function link(scope, iElement, iAttrs, controller) { ... }
    連結函數負責註冊DOM事件和更新DOM。它是在模板被複製之後執行的,它也是大部分指令邏輯代碼編寫的地方。
    scope - 指令需要監聽的範圍。
    iElement - instance element - 指令所在的元素。只有在postLink函數中對元素的子項目進行操作才是安全的,因為那時它們才已經全部連結好。
    iAttrs - instance attributes - 執行個體屬性,一個標準化的、所有聲明在當前元素上的屬性列表,這些屬性在所有連結函數間是共用的。
    controller - 控制器執行個體,也就是當前指令通過require請求的指令someDirective內部的controller。比如:someDirective指令中的controller:function(){this.Say = function(){}},那麼,在當前指令的link函數中,你就可以通過controller.Say進行調用了。
    Pre-linking function 在子項目被連結前執行。不能用來進行DOM的變形,以防連結函數找不到正確的元素來連結。
    Post-linking function 所有元素都被連結後執行。

  compile function 和 link function需要注意的地方:兩者是互斥的,compile function負責對模板dom進行修改,link function負責將範圍和dom進行串連。

                          當兩者共存時,compile function返回的函數當作link function,link function則被忽略。

  

    

 

  

  

 

 

 

  

    

AngularJS 講解,四 Directive

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.