理解AngularJs指令
對于指令,可以把它簡單的理解成在特定DOM元素上運行的函數(shù),指令可以擴展這個元素的功能。
首先來看個完整的參數(shù)示例再來詳細的介紹各個參數(shù)的作用及用法:
angular.module('myApp', [])
.directive('myDirective', function() {
return {
restrict: String,
priority: Number,
terminal: Boolean,
template: String or Template Function:
function(tElement, tAttrs) {...},
templateUrl: String,
replace: Boolean or String,
scope: Boolean or Object,
transclude: Boolean,
controller: String or
function(scope, element, attrs, transclude, otherInjectables) { ... },
controllerAs: String,
require: String,
link: function(scope, iElement, iAttrs) { ... },
compile: // 返回一個對象或連接函數(shù),如下所示:
function(tElement, tAttrs, transclude) {
return {
pre: function(scope, iElement, iAttrs, controller) { ... },
post: function(scope, iElement, iAttrs, controller) { ... }
}
return function postLink(...) { ... }
}
};
});
1、restrict[string]
restrict是一個可選的參數(shù)。用于指定該指令在DOM中以何種形式被聲明。默認值是A,即以屬性的形式來進行聲明。
可選值如下:
E(元素)
<my-directive></my-directive>
A(屬性,默認值)
<div my-directive="expression"></div>
C(類名)
<div class="my-directive:expression;"></div>
M(注釋)
<--directive:my-directive expression-->
一般考慮到瀏覽器的兼容性,強烈建議使用默認的屬性就可以即即以屬性的形式來進行聲明。最后一種方式建議再不要求逼格指數(shù)的時候千萬不要用。
Code:
angular.module('app',[])
.directive('myDirective', function () {
return {
restrict: 'E',
template: '<a
};
})
HtmlCode:
<my-directive></my-directive>
效果:
2、priority[int]
大多數(shù)指令會忽略這個參數(shù),使用默認值0,但也有些場景設置高優(yōu)先級是非常重要甚至是必須的。例如,ngRepeat將這個參數(shù)設置為1000,這樣就可以保證在同一元素上,它總是在其他指令之前被調(diào)用。
3、terminal[bool]
這個參數(shù)用來停止運行當前元素上比本指令優(yōu)先級低的指令。但同當前指令優(yōu)先級相同的指令還是會被執(zhí)行。
例如:ngIf的優(yōu)先級略高于ngView(它們操控的實際就是terminal參數(shù)),如果ngIf的表達式值為true,ngView就可以被正常執(zhí)行,但如果ngIf表達式的值為false,由于ngView的優(yōu)先級較低就不會被執(zhí)行。
4、template[string or function]
template參數(shù)是可選的,必須被設置為以下兩種形式之一:
- 一段HTML文本;
- 一個可以接受兩個參數(shù)的函數(shù),參數(shù)為tElement和tAttrs,并返回一個代表模板的字符串。tElement和tAttrs中的t代表template,是相對于instance的。
首先演示下第二種用法:
angular.module('app',[])
.directive('myDirective', function () {
return {
restrict: 'EAC',
template: function (elem, attr) {
return "<a href='" + attr.value + "'>" + attr.text + "</a>";
}
};
})
HtmlCode:(效果同上,不做演示了)
<my-directive value="http://www.baidu.com" text="百度"></my-directive>
<div my-directive
value="http://www.baidu.com"
text="百度"></div>
5、templateUrl[string or function]
templateUrl是可選的參數(shù),可以是以下類型:
- 一個代表外部HTML文件路徑的字符串;
- 一個可以接受兩個參數(shù)的函數(shù),參數(shù)為tElement和tAttrs,并返回一個外部HTML文件路徑的字符串。
無論哪種方式,模板的URL都將通過ng內(nèi)置的安全層,特別是$getTrustedResourceUrl,這樣可以保護模板不會被不信任的源加載。 默認情況下,調(diào)用指令時會在后臺通過Ajax來請求HTML模板文件。加載大量的模板將嚴重拖慢一個客戶端應用的速度。為了避免延遲,可以在部署應用之前對HTML模板進行緩存。
Code:
angular.module('app',[])
.directive('myDirective', function () {
return {
restrict: 'AEC',
templateUrl: function (elem, attr) {
return attr.value + ".html"; //當然這里我們可以直接指定路徑,同時在模板中可以包含表達式
}
};
})
6、replace[bool]
replace是一個可選參數(shù),如果設置了這個參數(shù),值必須為true,因為默認值為false。默認值意味著模板會被當作子元素插入到調(diào)用此指令的元素內(nèi)部,
例如上面的示例默認值情況下,生成的html代碼如下:
<my-directive value="http://www.baidu.com" text="百度"><a >百度</a></my-directive>
如果設置replace=true
<a value="http://www.baidu.com" text="百度">百度</a>
據(jù)我觀察,這種效果只有設置restrict="E"的情況下,才會表現(xiàn)出實際效果。
介紹完基本的指令參數(shù)后,就要涉及到更重要的作用域參數(shù)了...
7、scope參數(shù)[bool or object]
scope參數(shù)是可選的,可以被設置為true或一個對象。默認值是false。
如果一個元素上有多個指令使用了隔離作用域,其中只有一個可以生效。只有指令模板中的根元素可以獲得一個新的作用域。因此,對于這些對象來說scope默認被設置為true。內(nèi)置指令ng-controller的作用,就是從父級作用域繼承并創(chuàng)建一個新的子作用域。它會創(chuàng)建一個新的從父作用域繼承而來的子作用域。這里的繼承就不在贅述,和面向對象中的繼承基本是一直的。
首先我們來分析一段代碼:
<div ng-app="app" ng-init="name= '祖父'">
<div ng-init="name='父親'">
第一代:{{ name }}
<div ng-init="name= '兒子'" ng-controller="SomeController">
第二代: {{ name }}
<div ng-init="name='孫子'">
第三代: {{ name }}
</div>
</div>
</div>
</div>
我們發(fā)現(xiàn)第一代,我們初始化name為父親,但是第二代和第三代其實是一個作用域,那么他們的name其實是一個對象,因此出現(xiàn)的效果如下:
第一代:父親
第二代: 孫子
第三代: 孫子
我們在修改一下代碼,把第三代隔離開來再看看效果:
<div ng-app="app"ng-init="name= '祖父'">
<div ng-init="name='父親'">
第一代:{{ name }}
<div ng-init="name= '兒子'" ng-controller="SomeController">
第二代: {{ name }}
<div ng-init="name='孫子'" ng-controller="SecondController">
第三代: {{ name }}
</div>
</div>
</div>
</div>
JsCode:
angular.module('app', [])
.controller('SomeController',function($scope) {
})
.controller('SecondController', function ($scope) {
})
效果如下:
第一代:父親
第二代: 兒子
第三代: 孫子
在修改下代碼來看看繼承:
<div ng-app="app"ng-init="name= '祖父的吻'">
<div>
第一代:{{ name }}
<div ng-controller="SomeController">
第二代: {{ name }}
<div ng-controller="SecondController">
第三代: {{ name }}
</div>
</div>
</div>
</div>
效果如下:
第一代:祖父的吻
第二代: 祖父的吻
第三代: 祖父的吻
如果要創(chuàng)建一個能夠從外部原型繼承作用域的指令,將scope屬性設置為true,簡單來說就是可繼承的隔離,即不能反向影響父作用域。
再來看個例子:
angular.module('myApp', [])
.controller('MainController', function ($scope) {
})
.directive('myDirective', function () {
return {
restrict: 'A',
scope:false,//切換為{},true測試
priority: 100,
template: '<div>內(nèi)部:{{ myProperty }}<input ng-model="myProperty"/></div>'
};
});
Html代碼:
<div ng-controller='MainController' ng-init="myProperty='Hello World!'">
外部: {{ myProperty}}
<input ng-model="myProperty" />
<div my-directive></div>
</div>
當我們改變scope的值我們會發(fā)現(xiàn)
false:繼承但不隔離

true:繼承并隔離

{}:隔離且不繼承

8、transclude
transclude是一個可選的參數(shù)。默認值是false。嵌入通常用來創(chuàng)建可復用的組件,典型的例子是模態(tài)對話框或導航欄。我們可以將整個模板,包括其中的指令通過嵌入全部傳入一個指令中。指令的內(nèi)部可以訪問外部指令的作用域,并且模板也可以訪問外部的作用域對象。為了將作用域傳遞進去,scope參數(shù)的值必須通過{}或true設置成隔離作用域。如果沒有設置scope參數(shù),那么指令內(nèi)部的作用域將被設置為傳入模板的作用域。
只有當你希望創(chuàng)建一個可以包含任意內(nèi)容的指令時,才使用transclude: true。
我們來看兩個例子-導航欄:
<div side-box title="TagCloud">
<div class="tagcloud">
<a href="">Graphics</a>
<a href="">ng</a>
<a href="">D3</a>
<a href="">Front-end</a>
<a href="">Startup</a>
</div>
</div>
JsCode:
angular.module('myApp', [])
.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>'
};
});
這段代碼告訴ng編譯器,將它從DOM元素中獲取的內(nèi)容放到它發(fā)現(xiàn)ng-transclude指令的地方。
再來你看個官網(wǎng)的例子:
angular.module('docsIsoFnBindExample', [])
.controller('Controller', ['$scope', '$timeout', 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()">×</a> <div ng-transclude></div> </div>
index.html
<div ng-controller="Controller">
<my-dialog ng-hide="dialogIsHidden" on-close="hideDialog()">
Check out the contents, {{name}}!
</my-dialog>
</div>
如果指令使用了transclude參數(shù),那么在控制器無法正常監(jiān)聽數(shù)據(jù)模型的變化了。建議在鏈接函數(shù)里使用$watch服務。
9、controller[string or function]
controller參數(shù)可以是一個字符串或一個函數(shù)。當設置為字符串時,會以字符串的值為名字,來查找注冊在應用中的控制器的構造函數(shù).
angular.module('myApp', [])
.directive('myDirective', function() {
restrict: 'A',
controller: 'SomeController'
})
可以在指令內(nèi)部通過匿名構造函數(shù)的方式來定義一個內(nèi)聯(lián)的控制器
angular.module('myApp',[])
.directive('myDirective', function() {
restrict: 'A',
controller:
function($scope, $element, $attrs, $transclude) {
// 控制器邏輯放在這里
}
});
我們可以將任意可以被注入的ng服務注入到控制器中,便可以在指令中使用它了??刂破髦幸灿幸恍┨厥獾姆湛梢员蛔⑷氲街噶町斨?。這些服務有:
1. $scope
與指令元素相關聯(lián)的當前作用域。
2. $element
當前指令對應的元素。
3. $attrs
由當前元素的屬性組成的對象。
<div id="aDiv"class="box"></div>
具有如下的屬性對象:
{
id: "aDiv",
class: "box"
}
4. $transclude
嵌入鏈接函數(shù)會與對應的嵌入作用域進行預綁定。transclude鏈接函數(shù)是實際被執(zhí)行用來克隆元素和操作DOM的函數(shù)。
angular.module('myApp',[])
.directive('myLink', function () {
return {
restrict: 'EA',
transclude: true,
controller:
function ($scope, $element,$attrs,$transclude) {
$transclude(function (clone) {
var a = angular.element('<a>');
a.attr('href', $attrs.value);
a.text(clone.text());
$element.append(a);
});
}
};
});
html
<my-link value="http://www.baidu.com">百度</my-link> <div my-link value="http://www.google.com">谷歌</div>
僅在compile參數(shù)中使用transcludeFn是推薦的做法。link函數(shù)可以將指令互相隔離開來,而controller則定義可復用的行為。如果我們希望將當前指令的API暴露給其他指令使用,可以使用controller參數(shù),否則可以使用link來構造當前指令元素的功能性(即內(nèi)部功能)。如果我們使用了scope.$watch()或者想要與DOM元素做實時的交互,使用鏈接會是更好的選擇。使用了嵌入,控制器中的作用域所反映的作用域可能與我們所期望的不一樣,這種情況下,$scope對象無法保證可以被正常更新。當想要同當前屏幕上的作用域交互時,可以使用傳入到link函數(shù)中的scope參數(shù)。
10、controllerAs[string]
controllerAs參數(shù)用來設置控制器的別名,這樣就可以在視圖中引用控制器甚至無需注入$scope。
<div ng-controller="MainController as main">
<input type="text" ng-model="main.name" />
<span>{{ main.name }}</span>
</div>
JsCode:
angular.module('myApp',[])
.controller('MainController', function () {
this.name = "Halower";
});
控制器的別名使路由和指令具有創(chuàng)建匿名控制器的強大能力。這種能力可以將動態(tài)的對象創(chuàng)建成為控制器,并且這個對象是隔離的、易于測試。
11、 require[string or string[]]
require為字符串代表另外一個指令的名字。require會將控制器注入到其所指定的指令中,并作為當前指令的鏈接函數(shù)的第四個參數(shù)。字符串或數(shù)組元素的值是會在當前指令的作用域中使用的指令名稱。在任何情況下,ng編譯器在查找子控制器時都會參考當前指令的模板。
如果不使用^前綴,指令只會在自身的元素上查找控制器。指令定義只會查找定義在指令作當前用域中的ng-model=""
如果使用?前綴,在當前指令中沒有找到所需要的控制器,會將null作為傳給link函數(shù)的第四個參數(shù)。
如果添加了^前綴,指令會在上游的指令鏈中查找require參數(shù)所指定的控制器。
如果添加了?^ 將前面兩個選項的行為組合起來,我們可選擇地加載需要的指令并在父指令鏈中進行查找
如果沒有任何前綴,指令將會在自身所提供的控制器中進行查找,如果沒有找到任何控制器(或具有指定名字的指令)就拋出一個錯誤
12、compile【object or function】
compile選項本身并不會被頻繁使用,但是link函數(shù)則會被經(jīng)常使用。本質上,當我們設置了link選項,實際上是創(chuàng)建了一個postLink() 鏈接函數(shù),以便compile() 函數(shù)可以定義鏈接函數(shù)。通常情況下,如果設置了compile函數(shù),說明我們希望在指令和實時數(shù)據(jù)被放到DOM中之前進行DOM操作,在這個函數(shù)中進行諸如添加和刪除節(jié)點等DOM操作是安全的。
compile和link選項是互斥的。如果同時設置了這兩個選項,那么會把compile所返回的函數(shù)當作鏈接函數(shù),而link選項本身則會被忽略。
編譯函數(shù)負責對模板DOM進行轉換。鏈接函數(shù)負責將作用域和DOM進行鏈接。 在作用域同DOM鏈接之前可以手動操作DOM。在實踐中,編寫自定義指令時這種操作是非常罕見的,但有幾個內(nèi)置指令提供了這樣的功能。
13、link
compile: function(tEle, tAttrs, transcludeFn) {
//todo:
return function(scope, ele, attrs) {
// 鏈接函數(shù)
};
鏈接函數(shù)是可選的。如果定義了編譯函數(shù),它會返回鏈接函數(shù),因此當兩個函數(shù)都定義時,編譯函數(shù)會重載鏈接函數(shù)。如果我們的指令很簡單,并且不需要額外的設置,可以從工廠函數(shù)(回調(diào)函數(shù))返回一個函數(shù)來代替對象。如果這樣做了,這個函數(shù)就是鏈接函數(shù)。
14、ngModel
它提供更底層的API來處理控制器內(nèi)的數(shù)據(jù),這個API用來處理數(shù)據(jù)綁定、驗證、 CSS更新等不實際操作DOM的事情,ngModel 控制器會隨 ngModel 被一直注入到指令中,其中包含了一些方法。為了訪問ngModelController必須使用require設置.
ngModelController常用的元素如下:
1).為了設置作用域中的視圖值,需要調(diào)用 ngModel.$setViewValue() 函數(shù)。
$setViewValue() 方法適合于在自定義指令中監(jiān)聽自定義事件(比如使用具有回調(diào)函數(shù)的jQuery插件),我們會希望在回調(diào)時設置$viewValue并執(zhí)行digest循環(huán)。
angular.module('myApp')
.directive('myDirective', function() {
return {
require: '?ngModel',
link: function(scope, ele, attrs, ngModel) {
if (!ngModel) return;
$(function() {
ele.datepicker({
//回調(diào)函數(shù)
onSelect: function(date) {
// 設置視圖和調(diào)用 apply
scope.$apply(function() {
ngModel.$setViewValue(date);
});
}
});
});
}
};
});
2).$render方法可以定義視圖具體的渲染方式
3).屬性(這里屬性可以參考前一篇文章末尾進行學習)
以上就是關于AngularJs指令的全部內(nèi)容,希望對大家的學習有所幫助。
相關文章
angular項目中bootstrap-datetimepicker時間插件的使用示例
這篇文章主要介紹了angular項目中bootstrap-datetimepicker時間插件的使用示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03
angular.js實現(xiàn)列表orderby排序的方法
今天小編就為大家分享一篇angular.js實現(xiàn)列表orderby排序的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-10-10
關于Angularjs中自定義指令一些有價值的細節(jié)和技巧小結
這篇文章主要介紹了關于Angularjs中自定義指令一些有價值的細節(jié)和技巧小結,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04
Ionic + Angular.js實現(xiàn)圖片輪播的方法示例
圖片輪播在我們?nèi)粘i_發(fā)中是再熟悉不過的了,下面這篇文章主要給大家介紹了Ionic + Angular實現(xiàn)圖片輪播的方法,文中給出了詳細的示例代碼供大家參考學習,需要的朋友們下面來一起看看吧。2017-05-05

