學習AngularJs:Directive指令用法(完整版)

本教程使用AngularJs版本:1.5.3javascript

AngularJs GitHub: https://github.com/angular/angular.js/css

AngularJs下載地址:https://angularjs.org/html

摘要:Directive(指令)筆者認爲是AngularJ很是強大而有有用的功能之一。它就至關於爲咱們寫了公共的自定義DOM元素或CLASS屬性或ATTR屬性,而且它不僅是單單如此,你還能夠在它的基礎上來操做scope、綁定事件、更改樣式等。經過這個Directive,咱們能夠封裝不少公共指令,好比分頁指令、自動補全指令等等。而後在HTML頁面裏只須要簡單的寫一行代碼就能夠實現不少強大的功能。通常狀況下,須要用Directive有下面的情景:
1. 使你的Html更具語義化,不須要深刻研究代碼和邏輯便可知道頁面的大體邏輯。
2. 抽象一個自定義組件,在其餘地方進行重用。java

1、Directive的定義及其使用方法
AngularJs的指令定義大體以下jquery

?
1
2
3
4
5
angular.module( "app" ,[]).directive( "directiveName" , function (){
  return {
  //經過設置項來定義
  };
})

Directive能夠放置於元素名、屬性、class、註釋中。下面是引用myDir這個directive的等價方式。(但不少directive都限制爲「屬性」的使用方式)git

?
1
2
3
4
5
6
7
< 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 >

以下一個實例 :angularjs

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!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 >

結果:github

下面是一個directive的詳細版express

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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;
  
});

2、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文本

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!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是一個函數時候的狀況

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!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頁面加載好的,將下列代碼做爲你頁面的一部分包含在裏面。

?
1
2
3
<script type= 'text/ng-template' id= 'hello.html' >
  <div><h1>Hi 我是林炳文~~~</h1></div>
</script>

這裏的id屬性就是被設置在templateUrl上用的。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!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 >

輸出結果:

另外一種辦法緩存是:

?
1
2
3
4
app.run([ "$templateCache" , function ($templateCache) {
  $templateCache.put( "hello.html" ,
  "<div><h1>Hi 我是林炳文~~~</h1></div>" );
}]);

使用實例以下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!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這個指令舉例,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!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 代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!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 都會同時更新屬性值,由於它們是雙向綁定的關係。

示例代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!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。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!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內容

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!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
能夠是一個字符串或者函數。

如果爲字符串,則將字符串當作是控制器的名字,來查找註冊在應用中的控制器的構造函數

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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連接函數只能在當前內部指令中定義行爲,且沒法再指令間複用。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!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操做。

它還有最簡單的用法就是

?
1
2
3
4
5
6
7
8
9
10
11
12
13
<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
這個選項的做用是能夠設置你的控制器的別名

通常之前咱們常常用這樣方式來寫代碼:

?
1
2
3
4
5
6
7
8
angular.module( "app" ,[])
  .controller( "demoController" ,[ "$scope" , function ($scope){
  $scope.title = "angualr" ;
  }])
  
  <div ng-app= "app" ng-controller= "demoController" >
  {{title}}
</div>

後來angularjs1.2給咱們帶來新語法糖,因此咱們能夠這樣寫

?
1
2
3
4
5
6
7
8
angular.module( "app" ,[])
  .controller( "demoController" ,[ function (){
  this .title = "angualr" ;
  }])
  
  <div ng-app= "app" ng-controller= "demoController as demo" >
  {{demo.title}}
  </div>

一樣的咱們也能夠再指令裏面也這樣寫

?
1
2
3
4
5
6
7
8
9
10
11
<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連接函數的第四個參數就能夠引用這些重合的方法了。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<!doctype html>
< html ng-app = "myApp" >
< head >
</ 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選項自己就會被忽略掉

1三、編譯函數 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函數的解釋。

1四、連接函數 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指令用法的所有內容,但願對你們的學習有所幫助。

相關文章
相關標籤/搜索