本教程使用AngularJs版本:1.5.3
AngularJs GitHub: https://github.com/angular/angular.js/
AngularJs下載地址:https://angularjs.org/
摘要:Directive(指令)筆者認為是AngularJ非常強大而有有用的功能之一。它就相當于為我們寫了公共的自定義DOM元素或CLASS屬性或ATTR屬性,并且它不只是單單如此,你還可以在它的基礎上來操作scope、綁定事件、更改樣式等。通過這個Directive,我們可以封裝很多公共指令,比如分頁指令、自動補全指令等等。然后在HTML頁面里只需要簡單的寫一行代碼就可以實現很多強大的功能。一般情況下,需要用Directive有下面的情景:
1. 使你的Html更具語義化,不需要深入研究代碼和邏輯即可知道頁面的大致邏輯。
2. 抽象一個自定義組件,在其他地方進行重用。
一、Directive的定義及其使用方法
AngularJs的指令定義大致如下
angular.module("app",[]).directive("directiveName",function(){  return{  //通過設置項來定義  }; }) Directive可以放置于元素名、屬性、class、注釋中。下面是引用myDir這個directive的等價方式。(但很多directive都限制為“屬性”的使用方式)
<span <span style="font-family: Arial, Helvetica, sans-serif;">directive-name</span><span style="font-family: Arial, Helvetica, sans-serif;">="exp"></span>//屬性</span> <span class="<span style="font-family: Arial, Helvetica, sans-serif;">directive-name</span>: exp;"></span>//class <<span style="font-family: Arial, Helvetica, sans-serif;">directive-name</span>></<span style="font-family: Arial, Helvetica, sans-serif;">directive-name</span>>//元素 <!-- directive: <span style="font-family: Arial, Helvetica, sans-serif;">directive-name </span><span style="font-family: Arial, Helvetica, sans-serif;">exp -->//注釋</span>
如下一個實例 :
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head>  <meta charset="UTF-8">  <title>AngularJS入門學習</title>  <script type="text/javascript" src="./1.5.3/angular.min.js"></script> </head> <body> <hello-world></hello-world> </body> <script type="text/javascript"> var app = angular.module('myApp', []); app.directive('helloWorld', function() {  return {  restrict: 'E',  template: '<div>Hi 我是林炳文~~~</div>',  replace: true  }; }); </script> </html> 結果:

下面是一個directive的詳細版
var myModule = angular.module(...);  myModule.directive('directiveName', function factory(injectables) {   var directiveDefinitionObject = {     priority: 0,     template: '<div></div>',     templateUrl: 'directive.html',     replace: false,     transclude: false,     restrict: 'A',     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;  }); 二、Directive指令內容解讀
可 以看到它有8個內容
1.restrict
(字符串)可選參數,指明指令在DOM里面以什么形式被聲明;取值有:E(元素),A(屬性),C(類),M(注釋),其中默認值為A;當然也可以兩個一起用,比如EA.表示即可以是元素也可以是屬性。
[html] view plain copy 在CODE上查看代碼片派生到我的代碼片
E(元素):<directiveName></directiveName>  
A(屬性):<div directiveName='expression'></div>  
C(類): <div class='directiveName'></div>  
M(注釋):<--directive:directiveName expression-->  
一般情況下E/A/C用得比較多。
2.priority
(數字),可選參數,指明指令的優先級,若在單個DOM上有多個指令,則優先級高的先執行;
3.terminal
(布爾型),可選參數,可以被設置為true或false,若設置為true,則優先級低于此指令的其他指令則無效,不會被調用(優先級相同的還是會執行)
4.template(字符串或者函數)可選參數,可以是:
(1)一段HTML文本
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head>  <meta charset="UTF-8">  <title>AngularJS入門學習</title>  <script type="text/javascript" src="./1.5.3/angular.min.js"></script> </head> <body> <hello-world></hello-world> </body> <script type="text/javascript"> var app = angular.module('myApp', []); app.directive('helloWorld', function() {  return {  restrict: 'E',  template: '<div><h1>Hi 我是林炳文~~~</h1></div>',  replace: true  }; }); </script> </html> 
(2)一個函數,可接受兩個參數tElement和tAttrs
其中tElement是指使用此指令的元素,而tAttrs則實例的屬性,它是一個由元素上所有的屬性組成的集合(對象)形如:
<hello-world2 title = '我是第二個directive'></hello-world2>  
其中title就是tattrs上的屬性
下面讓我們看看template是一個函數時候的情況
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head>  <meta charset="UTF-8">  <title>AngularJS入門學習</title>  <script type="text/javascript" src="./1.5.3/angular.min.js"></script> </head> <body> <hello-world></hello-world> <hello-world2 title = '我是第二個directive'></hello-world2> </body> <script type="text/javascript"> var app = angular.module('myApp', []); app.directive('helloWorld', function() {  return {  restrict: 'E',  template: '<div><h1>Hi 我是林炳文~~~</h1></div>',  replace: true  }; }); app.directive("helloWorld2",function(){  return{  restrict:'EAC',  template: function(tElement,tAttrs){  var _html = '';  _html += '<div>' +'hello '+tAttrs.title+'</div>';  return _html;  }  };  }); </script> </html> 結果:

可以看到指令中還用到了hello-world2中的標簽中的 title字段
5.templateUrl(字符串或者函數),可選參數,可以是
(1)一個代表HTML文件路徑的字符串
(2)一個函數,可接受兩個參數tElement和tAttrs(大致同上)
注意:在本地開發時候,需要運行一個服務器,不然使用templateUrl會報錯 Cross Origin Request Script(CORS)錯誤。由于加載html模板是通過異步加載的,若加載大量的模板會拖慢網站的速度,這里有個技巧,就是先緩存模板
你可以再你的index頁面加載好的,將下列代碼作為你頁面的一部分包含在里面。
<script type='text/ng-template' id='hello.html'> <div><h1>Hi 我是林炳文~~~</h1></div> </script>
這里的id屬性就是被設置在templateUrl上用的。
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head>  <meta charset="UTF-8">  <title>AngularJS入門學習</title>  <script type="text/javascript" src="./1.5.3/angular.min.js"></script> </head> <body> <hello-world></hello-world> </body> <script type="text/javascript"> var app = angular.module('myApp', []); app.directive('helloWorld', function() {  return {  restrict: 'E',  templateUrl: 'hello.html',  replace: true  }; }); </script> <script type='text/ng-template' id='hello.html'>  <div><h1>Hi 我是林炳文~~~</h1></div> </script> </html> 輸出結果:

另一種辦法緩存是:
app.run(["$templateCache", function($templateCache) {  $templateCache.put("hello.html",  "<div><h1>Hi 我是林炳文~~~</h1></div>"); }]); 使用實例如下:
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head>  <meta charset="UTF-8">  <title>AngularJS入門學習</title>  <script type="text/javascript" src="./1.5.3/angular.min.js"></script> </head> <body> <hello-world></hello-world> </body> <script type="text/javascript"> var app = angular.module('myApp', []); app.directive('helloWorld', function() {  return {  restrict: 'E',  templateUrl: 'hello.html',  replace: true  }; }); app.run(["$templateCache", function($templateCache) {  $templateCache.put("hello.html",  "<div><h1>Hi 我是林炳文~~~</h1></div>"); }]); </script> </html> 結果:

其實第一種方法還好一些,寫起來會比較快,筆者就得最多的也是第一種寫法,直接包在scprit當中
 6.replace
(布爾值),默認值為false,設置為true時候,我們再來看看下面的例子(對比下在template時候舉的例子)
            
     
replace為true時,hello-world這個標簽不在了,反之,則存在。
7.scope
(1)默認值false。表示繼承父作用域;
(2)true。表示繼承父作用域,并創建自己的作用域(子作用域);
(3){}。表示創建一個全新的隔離作用域;
7.1首先我們先來了解下scope的繼承機制。我們用ng-controller這個指令舉例,
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head>  <meta charset="UTF-8">  <title>AngularJS入門學習</title>  <script type="text/javascript" src="./1.5.3/angular.min.js"></script> </head> <body> <div ng-controller='MainController'>  父親:{{name}}<input ng-model="name" />  <div my-directive></div>  </div> </body> <script type="text/javascript"> var app = angular.module('myApp', []); app.controller('MainController', function ($scope) {  $scope.name = '林炳文'; }); app.directive('myDirective', function () {  return {  restrict: 'EA',  scope:false,  template: '<div>兒子:{{ name }}<input ng-model="name"/></div>'  }; }); </script> </html> 接下來我們通過一個簡單明了的例子來說明scope取值不同的差別:
scope:false

scope:true

scope:{}

當為false時候,兒子繼承父親的值,改變父親的值,兒子的值也隨之變化,反之亦如此。(繼承不隔離)
當為true時候,兒子繼承父親的值,改變父親的值,兒子的值隨之變化,但是改變兒子的值,父親的值不變。(繼承隔離)
當為{}時候,沒有繼承父親的值,所以兒子的值為空,改變任何一方的值均不能影響另一方的值。(不繼承隔離)
tip:當你想要創建一個可重用的組件時隔離作用域是一個很好的選擇,通過隔離作用域我們確保指令是‘獨立'的,并可以輕松地插入到任何HTML app中,并且這種做法防止了父作用域被污染;
7.2隔離作用域可以通過綁定策略來訪問父作用域的屬性。
directive 在使用隔離 scope 的時候,提供了三種方法同隔離之外的地方交互。這三種分別是
@ 綁定一個局部 scope 屬性到當前 dom 節點的屬性值。結果總是一個字符串,因為 dom 屬性是字符串。
& 提供一種方式執行一個表達式在父 scope 的上下文中。如果沒有指定 attr 名稱,則屬性名稱為相同的本地名稱。
= 通過 directive 的 attr 屬性的值在局部 scope 的屬性和父 scope 屬性名之間建立雙向綁定。
@ 局部 scope 屬性
@ 方式局部屬性用來訪問 directive 外部環境定義的字符串值,主要是通過 directive 所在的標簽屬性綁定外部字符串值。這種綁定是單向的,即父 scope 的綁定變化,directive 中的 scope 的屬性會同步變化,而隔離 scope 中的綁定變化,父 scope 是不知道的。
如下示例:directive 聲明未隔離 scope 類型,并且使用@綁定 name 屬性,在 directive 中使用 name 屬性綁定父 scope 中的屬性。當改變父 scope 中屬性的值的時候,directive 會同步更新值,當改變 directive 的 scope 的屬性值時,父 scope 無法同步更新值。
js 代碼:
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head>  <meta charset="UTF-8">  <title>AngularJS入門學習</title>  <script type="text/javascript" src="./1.5.3/angular.min.js"></script> </head> <body> <div ng-controller="myController">  <div class="result">  <div>父scope:  <div>Say:{{name}}<br>改變父scope的name:<input type="text" value="" ng-model="name"/></div>  </div>  <div>隔離scope:  <div isolated-directive name="{{name}}"></div>  </div>  <div>隔離scope(不使用父scope {{name}}):  <div isolated-directive name="name"></div>  </div>  </div> </body> <script type="text/javascript"> var app = angular.module('myApp', []);  app.controller("myController", function ($scope) {  $scope.name = "hello world";  }).directive("isolatedDirective", function () {  return {  scope: {  name: "@"  },  template: 'Say:{{name}} <br>改變隔離scope的name:<input type="buttom" value="" ng-model="name" class="ng-pristine ng-valid">'  }; }); </script> </html> 結果:頁面初始效果

動畫效果:

可以看到父scope上的內容發生改變,子scope同時發生改變。而子scope上的內容發生改變。不影響父scope上的內容!
= 局部 scope 屬性
= 通過 directive 的 attr 屬性的值在局部 scope 的屬性和父 scope 屬性名之間建立雙向綁定。
意思是,當你想要一個雙向綁定的屬性的時候,你可以使用=來引入外部屬性。無論是改變父 scope 還是隔離 scope 里的屬性,父 scope 和隔離 scope 都會同時更新屬性值,因為它們是雙向綁定的關系。
示例代碼:
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head>  <meta charset="UTF-8">  <title>AngularJS入門學習</title>  <script type="text/javascript" src="./1.5.3/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"> var app = angular.module('myApp', []);  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> 效果:

可以看到父scope和子scope上的內容一直都是一樣的!
& 局部 scope 屬性
& 方式提供一種途經是 directive 能在父 scope 的上下文中執行一個表達式。此表達式可以是一個 function。
比如當你寫了一個 directive,當用戶點擊按鈕時,directive 想要通知 controller,controller 無法知道 directive 中發生了什么,也許你可以通過使用 angular 中的 event 廣播來做到,但是必須要在 controller 中增加一個事件監聽方法。
最好的方法就是讓 directive 可以通過一個父 scope 中的 function,當 directive 中有什么動作需要更新到父 scope 中的時候,可以在父 scope 上下文中執行一段代碼或者一個函數。
如下示例在 directive 中執行父 scope 的 function。
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head>  <meta charset="UTF-8">  <title>AngularJS入門學習</title>  <script type="text/javascript" src="./1.5.3/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"> var app = angular.module('myApp', []);  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> 效果:

指令的內容比較多,下面再來講講transclude、compline、link、contrller
8.transclude
 如果不想讓指令內部的內容被模板替換,可以設置這個值為true。一般情況下需要和ngTransclude指令一起使用。 比如:template:"<div>hello every <div ng-transclude></div></div>",這時,指令內部的內容會嵌入到ng-transclude這個div中。也就是變成了<div>hello every <div>這是指令內部的內容</div></div>。默認值為false;這個配置選項可以讓我們提取包含在指令那個元素里面的內容,再將它放置在指令模板的特定位置。當你開啟transclude后,你就可以使用ng-transclude來指明了應該在什么地方放置transcluded內容
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head>  <meta charset="UTF-8">  <title>AngularJS入門學習</title>  <script type="text/javascript" src="./1.5.3/angular.min.js"></script> </head> <div sidebox title="Links">   <ul>   <li>First link</li>   <li>Second link</li>   </ul> </div> </body> <script type="text/javascript"> var app = angular.module('myApp', []); app.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>'  }; }); </script> </html> 結果:

當 transclude: false,時

如果指令使用了transclude參數,那么在控制器無法正常監聽數據模型的變化了。建議在鏈接函數里使用$watch服務。
9.controller
可以是一個字符串或者函數。
若是為字符串,則將字符串當做是控制器的名字,來查找注冊在應用中的控制器的構造函數
angular.module('myApp', []) .directive('myDirective', function() { restrict: 'A', // 始終需要 controller: 'SomeController' }) // 應用中其他的地方,可以是同一個文件或被index.html包含的另一個文件 angular.module('myApp') .controller('SomeController', function($scope, $element, $attrs, $transclude) { // 控制器邏輯放在這里 }); 也可以直接在指令內部的定義為匿名函數,同樣我們可以再這里注入任何服務($log,$timeout等等)[html] view plain copy 在CODE上查看代碼片派生到我的代碼片angular.module('myApp',[]) .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="myApp"> <head>  <meta charset="UTF-8">  <title>AngularJS入門學習</title>  <script type="text/javascript" src="./1.5.3/angular.min.js"></script> </head>  <hello mycolor ="red">我是林炳文~~~</hello> </body> <script type="text/javascript"> var app = angular.module('myApp', []); 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> 輸出結果:

并且在控制臺下輸出hello everyone
讓我們看看$transclude();在這里,它可以接收兩個參數,第一個是$scope,作用域,第二個是帶有參數clone的回調函數。而這個clone實際上就是嵌入的內容(經過jquery包裝),可以在它上做很多DOM操作。
它還有最簡單的用法就是
<script>  angular.module('myApp',[]).directive('mySite', function () {  return {   restrict: 'EA',   transclude: true,   controller:   function ($scope, $element,$attrs,$transclude,$log) {   var a = $transclude(); //$transclude()就是嵌入的內容   $element.append(a);   }  };  });  </script> 注意:使用$transclude會生成一個新的作用域。
默認情況下,如果我們簡單實用$transclude(),那么默認的其作用域就是$transclude生成的作用域
但是如果我們實用$transclude($scope,function(clone){}),那么作用域就是directive的作用域了
那么問題又來了。如果我們想實用父作用域呢
可以使用$scope.$parent
同理想要一個新的作用域也可以使用$scope.$parent.new();
10.controllerAs
這個選項的作用是可以設置你的控制器的別名
一般以前我們經常用這樣方式來寫代碼:
angular.module("app",[])  .controller("demoController",["$scope",function($scope){  $scope.title = "angualr";  }])   <div ng-app="app" ng-controller="demoController">  {{title}} </div> 后來angularjs1.2給我們帶來新語法糖,所以我們可以這樣寫
angular.module("app",[])  .controller("demoController",[function(){  this.title = "angualr";  }])   <div ng-app="app" ng-controller="demoController as demo">  {{demo.title}}  </div> 同樣的我們也可以再指令里面也這樣寫
<script>  angular.module('myApp',[]).directive('mySite', function () {  return {   restrict: 'EA',   transclude: true,   controller:'someController',   controllerAs:'mainController'   //..其他配置  };  });  </script> 11.require(字符串或者數組)
字符串代表另一個指令的名字,它將會作為link函數的第四個參數。具體用法我們可以舉個例子說明。假設現在我們要編寫兩個指令,兩個指令中的link鏈接函數中(link函數后面會講)存在有很多重合的方法,這時候我們就可以將這些重復的方法寫在第三個指令的controller中(上面也講到controller經常用來提供指令間的復用行為)然后在這兩個指令中,require這個擁有controller字段的的指令(第三個指令),
最后通過link鏈接函數的第四個參數就可以引用這些重合的方法了。
<!doctype html> <html ng-app="myApp"> <head>  <script src="http://cdn.staticfile.org/angular.js/1.2.10/angular.min.js"></script> </head> <body>     <outer-directive>  <inner-directive></inner-directive>  <inner-directive2></inner-directive2>  </outer-directive>  <script>  var app = angular.module('myApp', []);  app.directive('outerDirective', function() {   return {   scope: {},   restrict: 'AE',   controller: function($scope) {    this.say = function(someDirective) {    console.log('Got:' + someDirective.message);    };   }   };  });  app.directive('innerDirective', function() {   return {   scope: {},   restrict: 'AE',   require: '^outerDirective',   link: function(scope, elem, attrs, controllerInstance) {    scope.message = "Hi,leifeng";    controllerInstance.say(scope);   }   };  });  app.directive('innerDirective2', function() {   return {   scope: {},   restrict: 'AE',   require: '^outerDirective',   link: function(scope, elem, attrs, controllerInstance) {    scope.message = "Hi,shushu";    controllerInstance.say(scope);   }   };  });    </script>  </body> </html> 上面例子中的指令innerDirective和指令innerDirective2復用了定義在指令outerDirective的controller中的方法
也進一步說明了,指令中的controller是用來讓不同指令間通信用的。
另外我們可以在require的參數值加上下面的某個前綴,這會改變查找控制器的行為:
(1)沒有前綴,指令會在自身提供的控制器中進行查找,如果找不到任何控制器,則會拋出一個error
(2)?如果在當前的指令沒有找到所需的控制器,則會將null傳給link連接函數的第四個參數
(3)^如果在當前的指令沒有找到所需的控制器,則會查找父元素的控制器
(4)?^組合
12.Anguar的指令編譯過程
首先加載angularjs庫,查找到ng-app指令,從而找到應用的邊界,
根據ng-app劃定的作用域來調用$compile服務進行編譯,angularjs會遍歷整個HTML文檔,并根據js中指令的定義來處理在頁面上聲明的各個指令按照指令的優先級(priority)排列,根據指令中的配置參數(template,place,transclude等)轉換DOM然后就開始按順序執行各指令的compile函數(如果指令上有定義compile函數)對模板自身進行轉換
注意:此處的compile函數是我們指令中配置的,跟上面說的$compile服務不一樣。每個compile函數執行完后都會返回一個link函數,所有的link函數會合成一個大的link函數
然后這個大的link函數就會被執行,主要做數據綁定,通過在DOM上注冊監聽器來動態修改scope中的數據,或者是使用$watchs監聽 scope中的變量來修改DOM,從而建立雙向綁定等等。若我們的指令中沒有配置compile函數,那我們配置的link函數就會運行,她做的事情大致跟上面complie返回之后所有的link函數合成的的大的link函數差不多。
所以:在指令中compile與link選項是互斥的,如果同時設置了這兩個選項,那么就會把compile所返回的函數當做是鏈接函數,而link選項本身就會被忽略掉
13、編譯函數 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函數的解釋。
14、鏈接函數 Linking function
function link(scope, iElement, iAttrs, controller) { ... }
鏈接函數負責注冊DOM事件和更新DOM。它是在模板被克隆之后執行的,它也是大部分指令邏輯代碼編寫的地方。
scope - 指令需要監聽的作用域。
iElement - instance element - 指令所在的元素。只有在postLink函數中對元素的子元素進行操作才是安全的,因為那時它們才已經全部鏈接好。
iAttrs - instance attributes - 實例屬性,一個標準化的、所有聲明在當前元素上的屬性列表,這些屬性在所有鏈接函數間是共享的。
controller - 控制器實例,也就是當前指令通過require請求的指令direct2內部的controller。比如:direct2指令中的controller:function(){this.addStrength = function(){}},那么,在當前指令的link函數中,你就可以通過controller.addStrength進行調用了。
Pre-linking function 在子元素被鏈接前執行。不能用來進行DOM的變形,以防鏈接函數找不到正確的元素來鏈接。
Post-linking function 所有元素都被鏈接后執行。
說明:
    compile選項本身并不會被頻繁使用,但是link函數則會被經常使用。本質上,當我們設置了link選項,實際上是創建了一個postLink() 鏈接函數,以便compile() 函數可以定義鏈接函數。通常情況下,如果設置了compile函數,說明我們希望在指令和實時數據被放到DOM中之前進行DOM操作,在這個函數中進行諸如添加和刪除節點等DOM操作是安全的。compile和link選項是互斥的。如果同時設置了這兩個選項,那么會把compile所返回的函數當作鏈接函數,而link選項本身則會被忽略。譯函數負責對模板DOM進行轉換。鏈接函數負責將作用域和DOM進行鏈接。 在作用域同DOM鏈接之前可以手動操作DOM。在實踐中,編寫自定義指令時這種操作是非常罕見的,但有幾個內置指令提供了這樣的功能。 鏈接函數是可選的。如果定義了編譯函數,它會返回鏈接函數,因此當兩個函數都定義時,編譯函數會重載鏈接函數。如果我們的指令很簡單,并且不需要額外的設置,可以從工廠函數(回調函數)返回一個函數來代替對象。如果這樣做了,這個函數就是鏈接函數。
本文轉載http://blog.csdn.net/evankaka
以上就是AngularJs:Directive指令用法的全部內容,希望對大家的學習有所幫助。
新聞熱點
疑難解答