學(xué)習(xí)AngularJs:Directive指令用法(完整版)
本教程使用AngularJs版本:1.5.3
AngularJs GitHub: https://github.com/angular/angular.js/
AngularJs下載地址:https://angularjs.org/
摘要:Directive(指令)筆者認為是AngularJ非常強大而有有用的功能之一。它就相當(dāng)于為我們寫了公共的自定義DOM元素或CLASS屬性或ATTR屬性,并且它不只是單單如此,你還可以在它的基礎(chǔ)上來操作scope、綁定事件、更改樣式等。通過這個Directive,我們可以封裝很多公共指令,比如分頁指令、自動補全指令等等。然后在HTML頁面里只需要簡單的寫一行代碼就可以實現(xiàn)很多強大的功能。一般情況下,需要用Directive有下面的情景:
1. 使你的Html更具語義化,不需要深入研究代碼和邏輯即可知道頁面的大致邏輯。
2. 抽象一個自定義組件,在其他地方進行重用。
一、Directive的定義及其使用方法
AngularJs的指令定義大致如下
angular.module("app",[]).directive("directiveName",function(){ return{ //通過設(shè)置項來定義 }; })
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入門學(xué)習(xí)</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>
結(jié)果:
下面是一個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指令內(nèi)容解讀
可 以看到它有8個內(nèi)容
1.restrict
(字符串)可選參數(shù),指明指令在DOM里面以什么形式被聲明;取值有:E(元素),A(屬性),C(類),M(注釋),其中默認值為A;當(dāng)然也可以兩個一起用,比如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
(數(shù)字),可選參數(shù),指明指令的優(yōu)先級,若在單個DOM上有多個指令,則優(yōu)先級高的先執(zhí)行;
3.terminal
(布爾型),可選參數(shù),可以被設(shè)置為true或false,若設(shè)置為true,則優(yōu)先級低于此指令的其他指令則無效,不會被調(diào)用(優(yōu)先級相同的還是會執(zhí)行)
4.template(字符串或者函數(shù))可選參數(shù),可以是:
(1)一段HTML文本
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head> <meta charset="UTF-8"> <title>AngularJS入門學(xué)習(xí)</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)一個函數(shù),可接受兩個參數(shù)tElement和tAttrs
其中tElement是指使用此指令的元素,而tAttrs則實例的屬性,它是一個由元素上所有的屬性組成的集合(對象)形如:
<hello-world2 title = '我是第二個directive'></hello-world2>
其中title就是tattrs上的屬性
下面讓我們看看template是一個函數(shù)時候的情況
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head> <meta charset="UTF-8"> <title>AngularJS入門學(xué)習(xí)</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>
結(jié)果:
可以看到指令中還用到了hello-world2中的標簽中的 title字段
5.templateUrl(字符串或者函數(shù)),可選參數(shù),可以是
(1)一個代表HTML文件路徑的字符串
(2)一個函數(shù),可接受兩個參數(shù)tElement和tAttrs(大致同上)
注意:在本地開發(fā)時候,需要運行一個服務(wù)器,不然使用templateUrl會報錯 Cross Origin Request Script(CORS)錯誤。由于加載html模板是通過異步加載的,若加載大量的模板會拖慢網(wǎng)站的速度,這里有個技巧,就是先緩存模板
你可以再你的index頁面加載好的,將下列代碼作為你頁面的一部分包含在里面。
<script type='text/ng-template' id='hello.html'> <div><h1>Hi 我是林炳文~~~</h1></div> </script>
這里的id屬性就是被設(shè)置在templateUrl上用的。
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head> <meta charset="UTF-8"> <title>AngularJS入門學(xué)習(xí)</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>
輸出結(jié)果:
另一種辦法緩存是:
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入門學(xué)習(xí)</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>
結(jié)果:
其實第一種方法還好一些,寫起來會比較快,筆者就得最多的也是第一種寫法,直接包在scprit當(dāng)中
6.replace
(布爾值),默認值為false,設(shè)置為true時候,我們再來看看下面的例子(對比下在template時候舉的例子)
replace為true時,hello-world這個標簽不在了,反之,則存在。
7.scope
(1)默認值false。表示繼承父作用域;
(2)true。表示繼承父作用域,并創(chuàng)建自己的作用域(子作用域);
(3){}。表示創(chuàng)建一個全新的隔離作用域;
7.1首先我們先來了解下scope的繼承機制。我們用ng-controller這個指令舉例,
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head> <meta charset="UTF-8"> <title>AngularJS入門學(xué)習(xí)</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:{}
當(dāng)為false時候,兒子繼承父親的值,改變父親的值,兒子的值也隨之變化,反之亦如此。(繼承不隔離)
當(dāng)為true時候,兒子繼承父親的值,改變父親的值,兒子的值隨之變化,但是改變兒子的值,父親的值不變。(繼承隔離)
當(dāng)為{}時候,沒有繼承父親的值,所以兒子的值為空,改變?nèi)魏我环降闹稻荒苡绊懥硪环降闹?。(不繼承隔離)
tip:當(dāng)你想要創(chuàng)建一個可重用的組件時隔離作用域是一個很好的選擇,通過隔離作用域我們確保指令是‘獨立'的,并可以輕松地插入到任何HTML app中,并且這種做法防止了父作用域被污染;
7.2隔離作用域可以通過綁定策略來訪問父作用域的屬性。
directive 在使用隔離 scope 的時候,提供了三種方法同隔離之外的地方交互。這三種分別是
@ 綁定一個局部 scope 屬性到當(dāng)前 dom 節(jié)點的屬性值。結(jié)果總是一個字符串,因為 dom 屬性是字符串。
& 提供一種方式執(zhí)行一個表達式在父 scope 的上下文中。如果沒有指定 attr 名稱,則屬性名稱為相同的本地名稱。
= 通過 directive 的 attr 屬性的值在局部 scope 的屬性和父 scope 屬性名之間建立雙向綁定。
@ 局部 scope 屬性
@ 方式局部屬性用來訪問 directive 外部環(huán)境定義的字符串值,主要是通過 directive 所在的標簽屬性綁定外部字符串值。這種綁定是單向的,即父 scope 的綁定變化,directive 中的 scope 的屬性會同步變化,而隔離 scope 中的綁定變化,父 scope 是不知道的。
如下示例:directive 聲明未隔離 scope 類型,并且使用@綁定 name 屬性,在 directive 中使用 name 屬性綁定父 scope 中的屬性。當(dāng)改變父 scope 中屬性的值的時候,directive 會同步更新值,當(dāng)改變 directive 的 scope 的屬性值時,父 scope 無法同步更新值。
js 代碼:
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head> <meta charset="UTF-8"> <title>AngularJS入門學(xué)習(xí)</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>
結(jié)果:頁面初始效果
動畫效果:
可以看到父scope上的內(nèi)容發(fā)生改變,子scope同時發(fā)生改變。而子scope上的內(nèi)容發(fā)生改變。不影響父scope上的內(nèi)容!
= 局部 scope 屬性
= 通過 directive 的 attr 屬性的值在局部 scope 的屬性和父 scope 屬性名之間建立雙向綁定。
意思是,當(dāng)你想要一個雙向綁定的屬性的時候,你可以使用=來引入外部屬性。無論是改變父 scope 還是隔離 scope 里的屬性,父 scope 和隔離 scope 都會同時更新屬性值,因為它們是雙向綁定的關(guān)系。
示例代碼:
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head> <meta charset="UTF-8"> <title>AngularJS入門學(xué)習(xí)</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上的內(nèi)容一直都是一樣的!
& 局部 scope 屬性
& 方式提供一種途經(jīng)是 directive 能在父 scope 的上下文中執(zhí)行一個表達式。此表達式可以是一個 function。
比如當(dāng)你寫了一個 directive,當(dāng)用戶點擊按鈕時,directive 想要通知 controller,controller 無法知道 directive 中發(fā)生了什么,也許你可以通過使用 angular 中的 event 廣播來做到,但是必須要在 controller 中增加一個事件監(jiān)聽方法。
最好的方法就是讓 directive 可以通過一個父 scope 中的 function,當(dāng) directive 中有什么動作需要更新到父 scope 中的時候,可以在父 scope 上下文中執(zhí)行一段代碼或者一個函數(shù)。
如下示例在 directive 中執(zhí)行父 scope 的 function。
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head> <meta charset="UTF-8"> <title>AngularJS入門學(xué)習(xí)</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中執(zhí)行父scope定義的方法" ng-click="action()"/>' } }) </script> </html>
效果:
指令的內(nèi)容比較多,下面再來講講transclude、compline、link、contrller
8.transclude
如果不想讓指令內(nèi)部的內(nèi)容被模板替換,可以設(shè)置這個值為true。一般情況下需要和ngTransclude指令一起使用。 比如:template:"<div>hello every <div ng-transclude></div></div>",這時,指令內(nèi)部的內(nèi)容會嵌入到ng-transclude這個div中。也就是變成了<div>hello every <div>這是指令內(nèi)部的內(nèi)容</div></div>。默認值為false;這個配置選項可以讓我們提取包含在指令那個元素里面的內(nèi)容,再將它放置在指令模板的特定位置。當(dāng)你開啟transclude后,你就可以使用ng-transclude來指明了應(yīng)該在什么地方放置transcluded內(nèi)容
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head> <meta charset="UTF-8"> <title>AngularJS入門學(xué)習(xí)</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>
結(jié)果:
當(dāng) transclude: false,時
如果指令使用了transclude參數(shù),那么在控制器無法正常監(jiān)聽數(shù)據(jù)模型的變化了。建議在鏈接函數(shù)里使用$watch服務(wù)。
9.controller
可以是一個字符串或者函數(shù)。
若是為字符串,則將字符串當(dāng)做是控制器的名字,來查找注冊在應(yīng)用中的控制器的構(gòu)造函數(shù)
angular.module('myApp', []) .directive('myDirective', function() { restrict: 'A', // 始終需要 controller: 'SomeController' }) // 應(yīng)用中其他的地方,可以是同一個文件或被index.html包含的另一個文件 angular.module('myApp') .controller('SomeController', function($scope, $element, $attrs, $transclude) { // 控制器邏輯放在這里 }); 也可以直接在指令內(nèi)部的定義為匿名函數(shù),同樣我們可以再這里注入任何服務(wù)($log,$timeout等等) [html] view plain copy 在CODE上查看代碼片派生到我的代碼片 angular.module('myApp',[]) .directive('myDirective', function() { restrict: 'A', controller: function($scope, $element, $attrs, $transclude) { // 控制器邏輯放在這里 } });
另外還有一些特殊的服務(wù)(參數(shù))可以注入
(1)$scope,與指令元素相關(guān)聯(lián)的作用域
(2)$element,當(dāng)前指令對應(yīng)的 元素
(3)$attrs,由當(dāng)前元素的屬性組成的對象
(4)$transclude,嵌入鏈接函數(shù),實際被執(zhí)行用來克隆元素和操作DOM的函數(shù)
注意: 除非是用來定義一些可復(fù)用的行為,一般不推薦在這使用。
指令的控制器和link函數(shù)(后面會講)可以進行互換。區(qū)別在于,控制器主要是用來提供可在指令間復(fù)用的行為但link鏈接函數(shù)只能在當(dāng)前內(nèi)部指令中定義行為,且無法再指令間復(fù)用。
<!DOCTYPE html> <html lang="zh" ng-app="myApp"> <head> <meta charset="UTF-8"> <title>AngularJS入門學(xué)習(xí)</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, //注意此處必須設(shè)置為true controller: function ($scope, $element,$attrs,$transclude,$log) { //在這里你可以注入你想注入的服務(wù) $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>
輸出結(jié)果:
并且在控制臺下輸出hello everyone
讓我們看看$transclude();在這里,它可以接收兩個參數(shù),第一個是$scope,作用域,第二個是帶有參數(shù)clone的回調(diào)函數(shù)。而這個clone實際上就是嵌入的內(nèi)容(經(jīng)過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()就是嵌入的內(nèi)容 $element.append(a); } }; }); </script>
注意:使用$transclude會生成一個新的作用域。
默認情況下,如果我們簡單實用$transclude(),那么默認的其作用域就是$transclude生成的作用域
但是如果我們實用$transclude($scope,function(clone){}),那么作用域就是directive的作用域了
那么問題又來了。如果我們想實用父作用域呢
可以使用$scope.$parent
同理想要一個新的作用域也可以使用$scope.$parent.new();
10.controllerAs
這個選項的作用是可以設(shè)置你的控制器的別名
一般以前我們經(jīng)常用這樣方式來寫代碼:
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(字符串或者數(shù)組)
字符串代表另一個指令的名字,它將會作為link函數(shù)的第四個參數(shù)。具體用法我們可以舉個例子說明。假設(shè)現(xiàn)在我們要編寫兩個指令,兩個指令中的link鏈接函數(shù)中(link函數(shù)后面會講)存在有很多重合的方法,這時候我們就可以將這些重復(fù)的方法寫在第三個指令的controller中(上面也講到controller經(jīng)常用來提供指令間的復(fù)用行為)然后在這兩個指令中,require這個擁有controller字段的的指令(第三個指令),
最后通過link鏈接函數(shù)的第四個參數(shù)就可以引用這些重合的方法了。
<!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復(fù)用了定義在指令outerDirective的controller中的方法
也進一步說明了,指令中的controller是用來讓不同指令間通信用的。
另外我們可以在require的參數(shù)值加上下面的某個前綴,這會改變查找控制器的行為:
(1)沒有前綴,指令會在自身提供的控制器中進行查找,如果找不到任何控制器,則會拋出一個error
(2)?如果在當(dāng)前的指令沒有找到所需的控制器,則會將null傳給link連接函數(shù)的第四個參數(shù)
(3)^如果在當(dāng)前的指令沒有找到所需的控制器,則會查找父元素的控制器
(4)?^組合
12.Anguar的指令編譯過程
首先加載angularjs庫,查找到ng-app指令,從而找到應(yīng)用的邊界,
根據(jù)ng-app劃定的作用域來調(diào)用$compile服務(wù)進行編譯,angularjs會遍歷整個HTML文檔,并根據(jù)js中指令的定義來處理在頁面上聲明的各個指令按照指令的優(yōu)先級(priority)排列,根據(jù)指令中的配置參數(shù)(template,place,transclude等)轉(zhuǎn)換DOM然后就開始按順序執(zhí)行各指令的compile函數(shù)(如果指令上有定義compile函數(shù))對模板自身進行轉(zhuǎn)換
注意:此處的compile函數(shù)是我們指令中配置的,跟上面說的$compile服務(wù)不一樣。每個compile函數(shù)執(zhí)行完后都會返回一個link函數(shù),所有的link函數(shù)會合成一個大的link函數(shù)
然后這個大的link函數(shù)就會被執(zhí)行,主要做數(shù)據(jù)綁定,通過在DOM上注冊監(jiān)聽器來動態(tài)修改scope中的數(shù)據(jù),或者是使用$watchs監(jiān)聽 scope中的變量來修改DOM,從而建立雙向綁定等等。若我們的指令中沒有配置compile函數(shù),那我們配置的link函數(shù)就會運行,她做的事情大致跟上面complie返回之后所有的link函數(shù)合成的的大的link函數(shù)差不多。
所以:在指令中compile與link選項是互斥的,如果同時設(shè)置了這兩個選項,那么就會把compile所返回的函數(shù)當(dāng)做是鏈接函數(shù),而link選項本身就會被忽略掉
13、編譯函數(shù) Compile function
function compile(tElement, tAttrs, transclude) { ... }
編譯函數(shù)是用來處理需要修改模板DOM的情況的。因為大部分指令都不需要修改模板,所以這個函數(shù)也不常用。需要用到的例子有ngTrepeat,這個是需要修改模板的,還有ngView這個是需要異步載入內(nèi)容的。編譯函數(shù)接受以下參數(shù)。
tElement - template element - 指令所在的元素。對這個元素及其子元素進行變形之類的操作是安全的。
tAttrs - template attributes - 這個元素上所有指令聲明的屬性,這些屬性都是在編譯函數(shù)里共享的。
transclude - 一個嵌入的鏈接函數(shù)function(scope, cloneLinkingFn)。
注意:在編譯函數(shù)里面不要進行任何DOM變形之外的操作。 更重要的,DOM監(jiān)聽事件的注冊應(yīng)該在鏈接函數(shù)中做,而不是編譯函數(shù)中。
編譯函數(shù)可以返回一個對象或者函數(shù)。
返回函數(shù) - 等效于在編譯函數(shù)不存在時,使用配置對象的link屬性注冊的鏈接函數(shù)。
返回對象 - 返回一個通過pre或post屬性注冊了函數(shù)的對象。參考下面pre-linking和post-liking函數(shù)的解釋。
14、鏈接函數(shù) Linking function
function link(scope, iElement, iAttrs, controller) { ... }
鏈接函數(shù)負責(zé)注冊DOM事件和更新DOM。它是在模板被克隆之后執(zhí)行的,它也是大部分指令邏輯代碼編寫的地方。
scope - 指令需要監(jiān)聽的作用域。
iElement - instance element - 指令所在的元素。只有在postLink函數(shù)中對元素的子元素進行操作才是安全的,因為那時它們才已經(jīng)全部鏈接好。
iAttrs - instance attributes - 實例屬性,一個標準化的、所有聲明在當(dāng)前元素上的屬性列表,這些屬性在所有鏈接函數(shù)間是共享的。
controller - 控制器實例,也就是當(dāng)前指令通過require請求的指令direct2內(nèi)部的controller。比如:direct2指令中的controller:function(){this.addStrength = function(){}},那么,在當(dāng)前指令的link函數(shù)中,你就可以通過controller.addStrength進行調(diào)用了。
Pre-linking function 在子元素被鏈接前執(zhí)行。不能用來進行DOM的變形,以防鏈接函數(shù)找不到正確的元素來鏈接。
Post-linking function 所有元素都被鏈接后執(zhí)行。
說明:
compile選項本身并不會被頻繁使用,但是link函數(shù)則會被經(jīng)常使用。本質(zhì)上,當(dāng)我們設(shè)置了link選項,實際上是創(chuàng)建了一個postLink() 鏈接函數(shù),以便compile() 函數(shù)可以定義鏈接函數(shù)。通常情況下,如果設(shè)置了compile函數(shù),說明我們希望在指令和實時數(shù)據(jù)被放到DOM中之前進行DOM操作,在這個函數(shù)中進行諸如添加和刪除節(jié)點等DOM操作是安全的。compile和link選項是互斥的。如果同時設(shè)置了這兩個選項,那么會把compile所返回的函數(shù)當(dāng)作鏈接函數(shù),而link選項本身則會被忽略。譯函數(shù)負責(zé)對模板DOM進行轉(zhuǎn)換。鏈接函數(shù)負責(zé)將作用域和DOM進行鏈接。 在作用域同DOM鏈接之前可以手動操作DOM。在實踐中,編寫自定義指令時這種操作是非常罕見的,但有幾個內(nèi)置指令提供了這樣的功能。 鏈接函數(shù)是可選的。如果定義了編譯函數(shù),它會返回鏈接函數(shù),因此當(dāng)兩個函數(shù)都定義時,編譯函數(shù)會重載鏈接函數(shù)。如果我們的指令很簡單,并且不需要額外的設(shè)置,可以從工廠函數(shù)(回調(diào)函數(shù))返回一個函數(shù)來代替對象。如果這樣做了,這個函數(shù)就是鏈接函數(shù)。
本文轉(zhuǎn)載http://blog.csdn.net/evankaka
以上就是AngularJs:Directive指令用法的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。
相關(guān)文章
使用AngularJS創(chuàng)建自定義的過濾器的方法
這篇文章主要介紹了使用AngularJS創(chuàng)建自定義的過濾器的方法,AngularJS是非常熱門的JavaScript庫,需要的朋友可以參考下2015-06-06利用Ionic2 + angular4實現(xiàn)一個地區(qū)選擇組件
ionic是一個移動端開發(fā)框架,使用hybird技術(shù),只要使用前端開發(fā)技術(shù)就可以開發(fā)出電腦端,安卓端和ios端的站點程序。下面這篇文章主要給大家介紹了關(guān)于利用Ionic2 + angular4實現(xiàn)一個地區(qū)選擇組件的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-07-07angular4 JavaScript內(nèi)存溢出問題
本篇文章主要介紹了angular4 JavaScript內(nèi)存溢出問題,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03理解Angular的providers給Http添加默認headers
本篇文章主要介紹了理解Angular的providers給Http添加默認headers,具有一定的參考價值,有興趣的同學(xué)可以了解一下2017-07-07angularjs實現(xiàn)過濾并替換關(guān)鍵字小功能
這篇文章主要為大家詳細介紹了angularjs實現(xiàn)過濾并替換關(guān)鍵字小功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09Angular動態(tài)添加、刪除輸入框并計算值實例代碼
這篇文章主要介紹了Angular動態(tài)添加、刪除輸入框并計算值實例代碼的相關(guān)資料,需要的朋友可以參考下2017-03-03詳解Angular-ui-BootStrap組件的解釋以及使用
這篇文章主要介紹了詳解Angular-ui-BootStrap組件的解釋以及使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07