欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

AngularJS創(chuàng)建自定義指令的方法詳解

 更新時(shí)間:2016年11月03日 10:51:21   作者:joeylin  
這篇文章主要介紹了AngularJS創(chuàng)建自定義指令的方法,詳細(xì)的分析了自定義指令的原理、實(shí)現(xiàn)步驟、實(shí)現(xiàn)方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下

本文實(shí)例講述了AngularJS創(chuàng)建自定義指令的方法。分享給大家供大家參考,具體如下:

這是一篇譯文,來自angular開發(fā)者說明的指令。主要面向已經(jīng)熟悉angular開發(fā)基礎(chǔ)的開發(fā)者。這篇文檔解釋了什么情況下需要創(chuàng)建自己的指令,和如何去創(chuàng)建指令。

什么是指令

從一個(gè)高的層面來講,指令是angular $compile服務(wù)的說明,當(dāng)特定的標(biāo)簽(屬性,元素名,或者注釋) 出現(xiàn)在DOM中的時(shí)候,它讓編譯器附加指定的行為到DOM上。

這個(gè)過程是很簡單的。angular內(nèi)部有很用這樣自帶的指令,比如說ngBind, ngView,就像你創(chuàng)建控制器和服務(wù)一樣,你也可以創(chuàng)建自己的指令。當(dāng)angular啟動的時(shí)候,Angular的編譯器分析html去匹配指令,這允許指令注冊行為或者改變DOM。

匹配指令

在寫指令之前,我們首先需要知道的是angular是如何匹配到一個(gè)指令的,在以下的例子我們說input元素匹配到ngModel指令.

<input ng-model="foo">

下面這種方法同樣也會匹配到ngModel:

<input data-ng:model="foo">

Angular會規(guī)范化一個(gè)元素的標(biāo)簽名和屬性名,以便確定哪一個(gè)元素匹配到哪一個(gè)指令。我們在js中是通過使用規(guī)范化后的駝峰式的名字來引用指令(比如ngModel)。在HTML中常常使用'-'劃定的屬性名字來調(diào)用指令(比如說ng-model).

規(guī)范化的處理過程:

-去掉元素或?qū)傩陨厦娴膞-和data-的前綴
-轉(zhuǎn)化':','-'和‘_-'形式的命名為駝峰式拼寫

以下例子展示了用不同的方式匹配到ngBind指令

<span ng-bind="name"></span> <br/>
<span ng:bind="name"></span> <br/>
<span ng_bind="name"></span> <br/>
<span data-ng-bind="name"></span> <br/>
<span x-ng-bind="name"></span> <br/>

Best Practice: 優(yōu)先使用'-'格式的命名(比如說ng-bind匹配ngBind)。如果你想在HTML驗(yàn)證工具中通過,你可以用'data-'前綴的方式(比如data-ng-bind)。其他格式的命名是因?yàn)闅v史遺留的原因存在,避免使用它們。

$compile服務(wù)可以基于元素的名字,屬性名,類名,和注釋來匹配指令

所有Angular內(nèi)部提供的指令都匹配屬性名,標(biāo)簽名,注釋,或者類名。以下不同的方式都可以被解析到

<my-dir></my-dir>
<span my-dir="exp"></span>
<!-- directive: my-dir exp -->
<span class="my-dir: exp;"></span>

Best Practice: 優(yōu)先利用標(biāo)簽名和屬性名的方式使用指令。這樣子更容易理解指定的元素匹配到了哪個(gè)元素。

Best Practice: 注釋的方式通常被用在DOM API限制創(chuàng)建跨越多個(gè)元素的指令,比如說table元素,限制重復(fù)嵌套,這樣就要用注釋的方式。在AngularJS 1.2版本中,通過使用ng-repeat-start 和 ng-repeat-end 作為一個(gè)更好的方案來解決這個(gè)問題。在可能的情況下,推薦使用這種方式。

文本和屬性的綁定

在編譯過程中,編譯器會使用$interpolate服務(wù)來檢測匹配到的文本和屬性值是否包含內(nèi)嵌表達(dá)式。這些表達(dá)式被注冊為watches,可以在digest循環(huán)時(shí)被更新。

<a ng-href="img/{{username}}.jpg">Hello {{username}}!</a>

ngAttr屬性的綁定

瀏覽器有些時(shí)候會對它認(rèn)為合法的屬性值非常的挑剔(就是某些元素的屬性是不可以任意賦值的,否則會報(bào)錯(cuò))。

比如:

<svg>
 <circle cx="{{cx}}"></circle>
</svg>

使用這樣的寫法時(shí),我們會發(fā)現(xiàn)控制臺中報(bào)錯(cuò)Error: Invalid value for attribute cx="{{cx}}". .這是由于SVG DOM API的限制,你不能簡單的寫為cx="{{cx}}".

使用ng-attr-cx 可以解決這個(gè)問題

如果一個(gè)綁定的屬性使用ngAttr前綴(或者ng-attr), 那么在綁定的時(shí)候?qū)粦?yīng)用到相應(yīng)的未前綴化的屬性,這種方式允許你綁定到需要馬上被瀏覽器處理的屬性上面(比如SVG元素的circle[cx]屬性)。

所以,我們可以這樣寫來修復(fù)以上的問題:

<svg>
 <circle ng-attr-cx="{{cx}}"></circle>
</svg>

創(chuàng)建指令

首先我們來談?wù)撓伦灾噶畹腁PI,跟controller一樣,指令是注冊在module上,不同的是,指令是通過module.directive API來注冊的。module.directive接受的是一個(gè)規(guī)范化的名字和工廠函數(shù),這個(gè)工廠函數(shù)返回一個(gè)包含不同配置的對象,這個(gè)對象用來告訴$compile服務(wù)如何進(jìn)行下一步處理。

工廠函數(shù)僅在編譯器第一次匹配到指令的時(shí)候調(diào)用一次。通常在工廠函數(shù)中執(zhí)行初始化的工作。該函數(shù)使用$injector.invoke調(diào)用,所以它可以像controller一樣進(jìn)行依賴注入。

Best Practice: 優(yōu)先返回一個(gè)定義好的對象,而不是返回一個(gè)函數(shù)。

接下來,我們先會了解一些常見的例子,然后再深入了解不同的配置項(xiàng)的原理和編譯過程。

Best Practice: 為了避免與某些未來的標(biāo)準(zhǔn)命名沖突,最好前綴化你自己的指令,比如你創(chuàng)建一個(gè)<carousel>指令,它可能會產(chǎn)生沖突,加入HTML7引入相同的元素。推薦使用兩三個(gè)單詞的前綴(比如btfCarousel),同樣不能使用ng或者其他可能與angular未來版本起沖突的前綴。

以下的例子中,我們統(tǒng)一使用my前綴。

模板擴(kuò)展的指令

當(dāng)你有大量代表客戶信息的模板。這個(gè)模板在你的代碼中重復(fù)了很多次,當(dāng)你改變一個(gè)地方的時(shí)候,你不得不在其他地方同時(shí)改動,這時(shí)候,你就要使用指令來簡化你的模板。

我們來創(chuàng)建一個(gè)指令,簡單的時(shí)候靜態(tài)模板來替換它的內(nèi)容。

<div ng-controller="Ctrl">
  <div my-customer></div>
 </div>

JS

angular.module('docsSimpleDirective', [])
 .controller('Ctrl', function($scope) {
 $scope.customer = {
  name: 'Naomi',
  address: '1600 Amphitheatre'
 };
 })
 .directive('myCustomer', function() {
 return {
  template: 'Name: {{customer.name}} Address: {{customer.address}}'
 };
 });

注意我們這里做了一些綁定,$compile編譯鏈接<div my-customer> </div>之后,它將會匹配子元素的指令。這意味著你可以組合一些指令。以下例子中你會看到如何做到這一點(diǎn)。

這個(gè)例子中,我們直接在template配置項(xiàng)里寫上模板,但是隨著模板大小的增加,這樣非常不優(yōu)雅。

Best Practice: 除非你的模板非常小,否則更好的是分割成單獨(dú)的hmtl文件,然后使用templateUrl選項(xiàng)來加載。

假如你熟悉ngInclude,templateUrl跟它非常類似。現(xiàn)在我們使用templateUrl方式重寫上面的例子:

<div ng-controller="Ctrl">
  <div my-customer></div>
 </div>

JS:

angular.module('docsTemplateUrlDirective', [])
 .controller('Ctrl', function($scope) {
 $scope.customer = {
  name: 'Naomi',
  address: '1600 Amphitheatre'
 };
 })
 .directive('myCustomer', function() {
 return {
  templateUrl: 'my-customer.html'
 };
 });

my-customer.html

Name: {{customer.name}} Address: {{customer.address}}

非常好,但是如果我們想讓我們的指令匹配標(biāo)簽名<my-customer>? 如果我們只是簡單的把<my-customer>元素放在hmtl上面,會發(fā)現(xiàn)沒有效果。

Note: 創(chuàng)建指令的時(shí)候,默認(rèn)僅使用屬性的方式。為了創(chuàng)建一個(gè)能由元素名字觸發(fā)的指令,你需要用到restrict配置。

restrict配置可以按如下方式設(shè)置:
-'A' 僅匹配屬性名字
-'E' 僅匹配元素名字
-'AE' 可以匹配到屬性名字或者元素名

所以,我們可以使用 restrict: 'E'配置我們指令。

<div ng-controller="Ctrl">
  <div my-customer></div>
 </div>

JS

angular.module('docsTemplateUrlDirective', [])
 .controller('Ctrl', function($scope) {
 $scope.customer = {
  name: 'Naomi',
  address: '1600 Amphitheatre'
 };
 })
 .directive('myCustomer', function() {
 return {
  restrict: 'E',
  templateUrl: 'my-customer.html'
 };
 });

my-customer.html

Name: {{customer.name}} Address: {{customer.address}}

Note: 什么時(shí)候使用屬性名或元素名呢? 當(dāng)創(chuàng)建一個(gè)含有自己模板的組件的時(shí)候,需要使用元素名,如果僅僅是為已有的元素添加功能的話,使用屬性名。

使用元素名做為myCustomer指令是非常正確的決定,因?yàn)槟悴皇怯靡恍?customer'行為來點(diǎn)綴元素,而是定義一個(gè)具有自己行為的元素作為customer組件。

隔離指令的作用域

上面我們的myCustomer指令已經(jīng)非常好了,但是它有個(gè)致命的缺陷,我們在給定的作用域內(nèi)僅能使用一次。

它現(xiàn)在的實(shí)現(xiàn)是,我們每次重用該指令的時(shí)候都要為它新創(chuàng)一個(gè)控制器。

<div ng-controller="NaomiCtrl">
 <my-customer></my-customer>
</div>
<hr>
<div ng-controller="IgorCtrl">
 <my-customer></my-customer>
</div>

JS

angular.module('docsScopeProblemExample', [])
 .controller('NaomiCtrl', function($scope) {
 $scope.customer = {
  name: 'Naomi',
  address: '1600 Amphitheatre'
 };
 })
 .controller('IgorCtrl', function($scope) {
 $scope.customer = {
  name: 'Igor',
  address: '123 Somewhere'
 };
 })
 .directive('myCustomer', function() {
 return {
  restrict: 'E',
  templateUrl: 'my-customer.html'
 };
 });

my-customer.html

Name: {{customer.name}} Address: {{customer.address}}

這很明顯不是一個(gè)好的解決方案。

我們想要做的是能夠把指令的作用域與外部的作用域隔離開來,然后映射外部的作用域到指令內(nèi)部的作用域??梢酝ㄟ^創(chuàng)建isolate scope來完成這個(gè)目的。這樣的話,我們使用指令的scope配置。

<div ng-controller="Ctrl">
 <my-customer customer="naomi"></my-customer>
 <hr>
 <my-customer customer="igor"></my-customer>
</div>

JS

angular.module('docsIsolateScopeDirective', [])
 .controller('Ctrl', function($scope) {
 $scope.naomi = { name: 'Naomi', address: '1600 Amphitheatre' };
 $scope.igor = { name: 'Igor', address: '123 Somewhere' };
 })
 .directive('myCustomer', function() {
 return {
  restrict: 'E',
  scope: {
  customer: '=customer'
  },
  templateUrl: 'my-customer.html'
 };
 });

my-customer.html

Name: {{customer.name}} Address: {{customer.address}}

首先看hmtl,第一個(gè)<my-customer>綁定內(nèi)部作用域的customer到naomi。這個(gè)naomi我們在控制器中已經(jīng)定義好了。第二個(gè)是綁定customer到igor。

現(xiàn)在看看scope是如何配置的。

//...
scope: {
 customer: '=customer'
},
//...

屬性名(customer)是myCustomer指令上isolated scope的變量名。它的值(=customer)告訴編譯器綁定到customer屬性。

Note: 指令作用域配置中的'=attr'屬性名是被規(guī)范化過后的名字,比如要綁定<div bind-to-this="thing">中的屬性,你就要使用'=bindToThis'的綁定。

對于屬性名和你想要綁定的值的名字一樣,你可以使用這樣的快捷語法:

//...
scope: {
 // same as '=customer'
 customer: '='
},
//...

使用isolated scope還有另外一個(gè)用處,那就是可以綁定不同的數(shù)據(jù)到指令內(nèi)部的作用域。

在我們的例子中,我們可以添加另外一個(gè)屬性vojta到我們的作用域,然后在我們的指令模板中訪問它。

<div ng-controller="Ctrl">
  <my-customer customer="naomi"></my-customer>
</div>

JS

angular.module('docsIsolationExample', [])
 .controller('Ctrl', function($scope) {
 $scope.naomi = { name: 'Naomi', address: '1600 Amphitheatre' };
 $scope.vojta = { name: 'Vojta', address: '3456 Somewhere Else' };
 })
 .directive('myCustomer', function() {
 return {
  restrict: 'E',
  scope: {
  customer: '=customer'
  },
  templateUrl: 'my-customer-plus-vojta.html'
 };
 });

my-customer-plus-vojta.html

Name: {{customer.name}} Address: {{customer.address}}
<hr>
Name: {{vojta.name}} Address: {{vojta.address}}

注意到,{{vojta.name}}和{{vojta.address}}都是空的,意味著他們是undefined, 雖然我們在控制器中定義了vojta,但是在指令內(nèi)部訪問不到。

就像它的名字暗示的一樣, 指令的isolate scope隔離了除了你添加到作用域:{}對象中的數(shù)據(jù)模型外的一切東西。這對于你要建立一個(gè)可重復(fù)使用的組件是非常有用的,因?yàn)樗柚沽顺四阆胍獋魅氲臄?shù)據(jù)模型外其他東西改變你數(shù)據(jù)模型的狀態(tài)。

Note: 正常情況下,作用域是原型繼承自父作用域。但是isolate scope沒有這樣的繼承。

Best Practice: 當(dāng)你想要使你的組件在應(yīng)用范圍內(nèi)可重用,那么使用scope配置去創(chuàng)建一個(gè)isolate scopes

創(chuàng)建一個(gè)操作DOM的指令

在這個(gè)例子中,我們會創(chuàng)建一個(gè)顯示當(dāng)前時(shí)間的指令,每秒一次更新DOM以正確的顯示當(dāng)前的時(shí)間。

指令修改DOM通常是在link配置中,link選項(xiàng)接受一個(gè)帶有如下標(biāo)簽的函數(shù)function link(scope,element,attrs) {...}其中:

-scope是angular scope對象
-element指令匹配的jqLite封裝的元素(angular內(nèi)部實(shí)現(xiàn)的類jquery的庫)
-attrs是一個(gè)帶有規(guī)范化后屬性名字和相應(yīng)值的對象

在我們的link函數(shù)中,我們更新顯示時(shí)間每秒一次,或者當(dāng)用戶改變指定綁定的時(shí)間格式字符串的時(shí)候。我們也要移除定時(shí)器,當(dāng)指令被刪除的時(shí)候,以避免引入內(nèi)存泄露。

<div ng-controller="Ctrl2">
 Date format: <input ng-model="format"> <hr/>
 Current time is: <span my-current-time="format"></span>
</div>

JS

angular.module('docsTimeDirective', [])
 .controller('Ctrl2', function($scope) {
 $scope.format = 'M/d/yy h:mm:ss a';
 })
 .directive('myCurrentTime', function($timeout, dateFilter) {
 function link(scope, element, attrs) {
  var format,
   timeoutId;
  function updateTime() {
  element.text(dateFilter(new Date(), format));
  }
  scope.$watch(attrs.myCurrentTime, function(value) {
  format = value;
  updateTime();
  });
  function scheduleUpdate() {
  // save the timeoutId for canceling
  timeoutId = $timeout(function() {
   updateTime(); // update DOM
   scheduleUpdate(); // schedule the next update
  }, 1000);
  }
  element.on('$destroy', function() {
  $timeout.cancel(timeoutId);
  });
  // start the UI update process.
  scheduleUpdate();
 }
 return {
  link: link
 };
 });

這里有很多東西值得注意的,就像module.controller API, module.directive中函數(shù)參數(shù)是依賴注入,因此,我們可以在Link函數(shù)內(nèi)部使用$timeout和dataFilter服務(wù)。

我們注冊了一個(gè)事件element.on('$destroy', ...), 是什么觸發(fā)了這個(gè)$destory事件呢?

AngularJS會觸發(fā)一些特定的事件,當(dāng)一個(gè)被angular編譯過的DOM元素被移除的時(shí)候,它會觸發(fā)一個(gè)$destory事件,同樣的,當(dāng)一個(gè)angular作用域被移除的時(shí)候,它會向下廣播$destory事件到所有監(jiān)聽的作用域。

通過監(jiān)聽事件,你可以移除可能引起內(nèi)存泄露的事件監(jiān)聽器,注冊在元素和作用域上的監(jiān)聽器在它們被移除的時(shí)候,會自動會清理掉,但是假如注冊一個(gè)事件在服務(wù)或者沒有被刪除的DOM節(jié)點(diǎn)上,你就必須手工清理,否則會有內(nèi)存泄露的風(fēng)險(xiǎn)。

Best Practice:執(zhí)行被移除的時(shí)候應(yīng)該做一些清理的操作, 可以使用element.on('$destroy', ...)或者scope.on('$destroy', ...)來運(yùn)行解除綁定的函數(shù),

創(chuàng)建包裹其他元素的指令

我們現(xiàn)在已經(jīng)實(shí)現(xiàn)了,使用isolate scopes傳遞數(shù)據(jù)模型到指令里面。但是有時(shí)候我們需要能夠傳遞一整個(gè)模板而不是字符串或者對象。讓我們通過創(chuàng)建'dialog box'組件來說明。這個(gè)'dialog box'組件應(yīng)該能夠包裹任意內(nèi)容。

要實(shí)現(xiàn)這個(gè),我們使用transclude配置

<div ng-controller="Ctrl">
 <my-dialog>Check out the contents, {{name}}!</my-dialog>
</div>

JS

angular.module('docsTransclusionDirective', [])
 .controller('Ctrl', function($scope) {
 $scope.name = 'Tobias';
 })
 .directive('myDialog', function() {
 return {
  restrict: 'E',
  transclude: true,
  templateUrl: 'my-dialog.html'
 };
 });

my-dialog.html

<div class="alert" ng-transclude>
</div>

這個(gè)transclude配置用來干嘛呢? transclude使帶有這個(gè)配置的指令的內(nèi)容能夠訪問指令外部的作用域。

參照以下例子,注意到我們增加了一個(gè)link函數(shù),在這個(gè)link函數(shù)內(nèi)部我們重定義了name屬性的值為Jeff,那么現(xiàn)在這個(gè){{name}}會被解析成哪個(gè)值呢?

<div ng-controller="Ctrl">
 <my-dialog>Check out the contents, {{name}}!</my-dialog>
</div>

JS

angular.module('docsTransclusionDirective', [])
 .controller('Ctrl', function($scope) {
 $scope.name = 'Tobias';
 })
 .directive('myDialog', function() {
 return {
  restrict: 'E',
  transclude: true,
  templateUrl: 'my-dialog.html',
  link: function (element, scope) {
  scope.name = 'Jeff';
  }
 };
 });

my-dialog.html

<div class="alert" ng-transclude>
</div>

一般,我們會認(rèn)為{{name}}會被解析為Jeff,然而這里,我們看到這個(gè)例子中的{{name}}還是被解析成了Tobias.

transclude配置改變了指令相互嵌套的方式,他使指令的內(nèi)容擁有任何指令外部的作用域,而不是內(nèi)部的作用域。為了實(shí)現(xiàn)這個(gè),它給指令內(nèi)容一次訪問外部作用域的機(jī)會。

這樣的行為對于包裹內(nèi)容的指令是非常有意義的。因?yàn)槿绻贿@樣的話,你就必須分別傳入每個(gè)你需要使用的數(shù)據(jù)模型。如果你需要傳入每個(gè)要使用的數(shù)據(jù)模型,那么你就無法做到適應(yīng)各種不同內(nèi)容的情況。

Best Practice: 僅當(dāng)你要創(chuàng)建一個(gè)包裹任意內(nèi)容的指令的時(shí)候使用transclude:true。

下一步,我們增加一個(gè)按鈕到'dialog box'組件里面,允許用戶使用指令綁定自己定義的行為。

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

JS

angular.module('docsIsoFnBindExample', [])
 .controller('Ctrl', 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>

我們想要通過在指令的作用域上調(diào)用,來運(yùn)行我們傳遞進(jìn)去的函數(shù),但是這個(gè)函數(shù)是運(yùn)行在定義時(shí)候的上下文(js通常都是這樣子的)。

先前我們看到如何scope配置使用'=prop',但是在上文的例子中,我們使用'&prop','&'綁定開放了一個(gè)函數(shù)到isolated scope,允許 isolated scope調(diào)用它,同時(shí)維持原來函數(shù)的作用域(這里的作用域都是指$scope)。所以當(dāng)一個(gè)用戶點(diǎn)擊x時(shí)候,就會運(yùn)行Ctrl控制器的close函數(shù)。

Best Practice: 當(dāng)你的指令想要開放一個(gè)API去綁定特定的行為,在scope配置中使用'&prop'.

創(chuàng)建一個(gè)添加事件監(jiān)聽器的指令

先前,我們使用link函數(shù)創(chuàng)建一個(gè)操作DOM元素的指令,基于上面的例子,我們創(chuàng)建一個(gè)在元素上添加事件監(jiān)聽的指令。

舉個(gè)例子,假如我們想要創(chuàng)建一個(gè)讓用戶可拖拽的元素,該怎么做呢?

Drag ME

JS

angular.module('dragModule', []).
 directive('myDraggable', function($document) {
 return function(scope, element, attr) {
  var startX = 0, startY = 0, x = 0, y = 0;
  element.css({
  position: 'relative',
  border: '1px solid red',
  backgroundColor: 'lightgrey',
  cursor: 'pointer'
  });
  element.on('mousedown', function(event) {
  // Prevent default dragging of selected content
  event.preventDefault();
  startX = event.screenX - x;
  startY = event.screenY - y;
  $document.on('mousemove', mousemove);
  $document.on('mouseup', mouseup);
  });
  function mousemove(event) {
  y = event.screenY - startY;
  x = event.screenX - startX;
  element.css({
   top: y + 'px',
   left: x + 'px'
  });
  }
  function mouseup() {
  $document.unbind('mousemove', mousemove);
  $document.unbind('mouseup', mouseup);
  }
 }
 });

創(chuàng)建相互通信的指令

你可以通過在模板使用指令來組合任何指令。

有時(shí)候,你想要一個(gè)指令從其他的指令上面創(chuàng)建

想象你想要一個(gè)帶有tab的容器,容器的內(nèi)容對應(yīng)于激活的tab。

<my-tabs>
  <my-pane title="Hello">
  <h5 id="creating-custom-directives_source_hello">Hello</h5>
  <p>Lorem ipsum dolor sit amet</p>
  </my-pane>
  <my-pane title="World">
  <h5 id="creating-custom-directives_source_world">World</h5>
  <em>Mauris elementum elementum enim at suscipit.</em>
  <p><a href ng-click="i = i + 1">counter: {{i || 0}}</a></p>
  </my-pane>
</my-tabs>

JS

angular.module('docsTabsExample', [])
 .directive('myTabs', function() {
 return {
  restrict: 'E',
  transclude: true,
  scope: {},
  controller: function($scope) {
  var panes = $scope.panes = [];
  $scope.select = function(pane) {
   angular.forEach(panes, function(pane) {
   pane.selected = false;
   });
   pane.selected = true;
  };
  this.addPane = function(pane) {
   if (panes.length == 0) {
   $scope.select(pane);
   }
   panes.push(pane);
  };
  },
  templateUrl: 'my-tabs.html'
 };
 })
 .directive('myPane', function() {
 return {
  require: '^myTabs',
  restrict: 'E',
  transclude: true,
  scope: {
  title: '@'
  },
  link: function(scope, element, attrs, tabsCtrl) {
  tabsCtrl.addPane(scope);
  },
  templateUrl: 'my-pane.html'
 };
 });

my-tabs.html

<div class="tabbable">
 <ul class="nav nav-tabs">
 <li ng-repeat="pane in panes" ng-class="{active:pane.selected}">
  <a href="" ng-click="select(pane)">{{pane.title}}</a>
 </li>
 </ul>
 <div class="tab-content" ng-transclude></div>
</div>

my-pane.html

<div class="tab-pane" ng-show="selected" ng-transclude>
</div>

myPane指令有一個(gè)require:'^myTabs'的配置,當(dāng)指令使用這個(gè)配置,$compile服務(wù)叫myTabs的指令并獲取它的控制器實(shí)例,如果沒有找到,將會拋出一個(gè)錯(cuò)誤。'^'前綴意味著指令在它的父元素上面搜索控制器(沒有'^'前綴的話,指令默認(rèn)會在自身的元素上面搜索指定的指令)。

這里myTabs的控制器是來自何處呢?通過使用controller配置可以為指令指定一個(gè)控制器, 上問例子中myTab就是使用這個(gè)配置。就像ngController, 這個(gè)配置為指令的模板綁定了一個(gè)控制器。

再看我們的myPane's定義,注意到link函數(shù)的最后一個(gè)參數(shù): tabCtrl,當(dāng)一個(gè)指令包含另一個(gè)指令(通過require方式),它會接收該指令的控制器實(shí)例作為link函數(shù)的第四個(gè)參數(shù),利用這個(gè),myPane可以調(diào)用myTabs的addPane函數(shù)。

精明的讀者可能想知道link跟controller之間的區(qū)別,最基本的區(qū)別就是控制器開放一個(gè)API(就是這個(gè)控制器實(shí)例可以被其他實(shí)例讀取到),link函數(shù)可以通過require與控制器交互。

Best Practice: 當(dāng)你要開放一個(gè)API給其他指令的時(shí)候使用控制器,否則使用link函數(shù)。

總結(jié)

這里我們講解了一個(gè)些指令的主要使用案例。每一個(gè)都可以作為你創(chuàng)建自己指令的很好的起點(diǎn)。

如果你想更深入的了解編譯的處理過程,可以查看compiler guide相關(guān)內(nèi)容

$compile API頁面有directive每個(gè)配置項(xiàng)的具體解釋,可以參閱。

希望本文所述對大家AngularJS程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • Angular2.js實(shí)現(xiàn)表單驗(yàn)證詳解

    Angular2.js實(shí)現(xiàn)表單驗(yàn)證詳解

    這篇文章主要介紹了Angular2.js實(shí)現(xiàn)表單驗(yàn)證的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • angular動態(tài)表單制作

    angular動態(tài)表單制作

    通過實(shí)例代碼給大家詳細(xì)講述了angular動態(tài)表單的制作方法,對此有需要的朋友參考下。
    2018-02-02
  • AngularJS上傳文件的示例代碼

    AngularJS上傳文件的示例代碼

    上傳文件在很多時(shí)候都能用到,這篇文章主要介紹了AngularJS上傳文件的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-11-11
  • Angular4學(xué)習(xí)筆記之準(zhǔn)備和環(huán)境搭建項(xiàng)目

    Angular4學(xué)習(xí)筆記之準(zhǔn)備和環(huán)境搭建項(xiàng)目

    這篇文章主要介紹了Angular4學(xué)習(xí)筆記之準(zhǔn)備和環(huán)境搭建項(xiàng)目,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • AngularJS基礎(chǔ)學(xué)習(xí)筆記之控制器

    AngularJS基礎(chǔ)學(xué)習(xí)筆記之控制器

    在AngularJS中,控制器是一個(gè)Javascript函數(shù)(類型/類),用來增強(qiáng)除了根作用域意外的作用域?qū)嵗摹.?dāng)你或者AngularJS本身通過<code>scope.$new</code>倆創(chuàng)建一個(gè)新的子作用域?qū)ο髸r(shí),有一個(gè)選項(xiàng)能讓你將它當(dāng)做參數(shù)傳遞給控制器。
    2015-05-05
  • 對Angular中單向數(shù)據(jù)流的深入理解

    對Angular中單向數(shù)據(jù)流的深入理解

    這篇文章主要給大家介紹了關(guān)于對Angular中單向數(shù)據(jù)流的深入理解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-03-03
  • AngularJS實(shí)現(xiàn)表單驗(yàn)證

    AngularJS實(shí)現(xiàn)表單驗(yàn)證

    客戶端表單驗(yàn)證是AngularJS里面最酷的功能之一。 AngularJS表單驗(yàn)證可以讓你從一開始就寫出一個(gè)具有交互性和可相應(yīng)的現(xiàn)代HTML5表單。在AngularJS中,有許多表單驗(yàn)證指令。在這里,我們將談?wù)剮讉€(gè)最流行指令,然后我們將討論如何編寫自定義的驗(yàn)證。
    2015-01-01
  • 使用AngularJS實(shí)現(xiàn)可伸縮的頁面切換的方法

    使用AngularJS實(shí)現(xiàn)可伸縮的頁面切換的方法

    這篇文章主要介紹了使用AngularJS實(shí)現(xiàn)可伸縮的頁面切換的方法,AngularJS是一款熱門的JavaScript庫,需要的朋友可以參考下
    2015-06-06
  • Angular resolve基礎(chǔ)用法詳解

    Angular resolve基礎(chǔ)用法詳解

    resolve保證了數(shù)據(jù)獲取后再進(jìn)行路由跳轉(zhuǎn),防止因?yàn)閿?shù)據(jù)延遲而出現(xiàn)短暫的空組件情況,本文就介紹一下Angular resolve基礎(chǔ)用法,感興趣的小伙伴們可以參考一下
    2018-10-10
  • Angular2 (RC4) 路由與導(dǎo)航詳解

    Angular2 (RC4) 路由與導(dǎo)航詳解

    這篇文章主要介紹了Angular2 (RC4) 路由與導(dǎo)航的相關(guān)資料,需要的朋友可以參考下
    2016-09-09

最新評論