摘要:可選參數(shù),布爾值或者對象默認(rèn)值為,可能取值默認(rèn)值。布爾值或者字符,默認(rèn)值為這個配置選項可以讓我們提取包含在指令那個元素里面的內(nèi)容,再將它放置在指令模板的特定位置。
前言
最近學(xué)習(xí)了下angularjs指令的相關(guān)知識,也參考了前人的一些文章,在此總結(jié)下。
歡迎批評指出錯誤的地方。
Angularjs指令定義的API
AngularJs的指令定義大致如下
angular.module("app",[]).directive("directiveName",function(){
return{ //通過設(shè)置項來定義 };
})
其中return返回的對象包含很多參數(shù),下面一一說明
你知道用AngularJs怎么定義指令嗎?0
1.restrict
(字符串)可選參數(shù),指明指令在DOM里面以什么形式被聲明;
取值有:E(元素),A(屬性),C(類),M(注釋),其中默認(rèn)值為A;
E(元素):
A(屬性):
你知道用AngularJs怎么定義指令嗎?1
例如restrict:‘EA’ 則表示指令在DOM里面可用元素形式和屬性形式被聲明;
一般來說,當(dāng)你創(chuàng)建一個有自己模板的組件的時候,需要使用元素名,如果僅僅是為為已有元素添加功能的話,就使用屬性名
注意:如果想支持IE8,則最好使用屬性和類形式來定義。 另外Angular從1.3.x開始, 已經(jīng)放棄支持IE8了.
2.priority
(數(shù)字),可選參數(shù),指明指令的優(yōu)先級,若在單個DOM上有多個指令,則優(yōu)先級高的先執(zhí)行;
設(shè)置指令的優(yōu)先級算是不常用的
比較特殊的的例子是,angularjs內(nèi)置指令的ng-repeat的優(yōu)先級為1000,ng-init的優(yōu)先級為450;
3.terminal
(布爾型),可選參數(shù),可以被設(shè)置為true或false,若設(shè)置為true,則優(yōu)先級低于此指令的其他指令則無效,不會被調(diào)用(優(yōu)先級相同的還是會執(zhí)行)
4.template(字符串或者函數(shù))可選參數(shù),可以是:
(1)一段HTML文本
angular.module("app",[]).directive("hello",function(){
return{ restrict:"EA", template:"" }; })hello world
HTML代碼為:
結(jié)果渲染后的HTML為:
hello world
(2)一個函數(shù),可接受兩個參數(shù)tElement和tAttrs
其中tElement是指使用此指令的元素,而tAttrs則實例的屬性,它是一個由元素上所有的屬性組成的集合(對象)形如:
{
title:‘a(chǎn)aaa’,
name:"leifeng"
}
下面讓我們看看template是一個函數(shù)時候的情況
angular.module("app",[]).directive("directitle",function(){
return{ restrict:"EAC", template: function(tElement,tAttrs){ var _html = ""; _html += ""+tAttrs.title+""; return _html; } }; })
HTML代碼:
渲染之后的HTML:
5.templateUrl(字符串或者函數(shù)),可選參數(shù),可以是
(1)一個代表HTML文件路徑的字符串
(2)一個函數(shù),可接受兩個參數(shù)tElement和tAttrs(大致同上)
注意:在本地開發(fā)時候,需要運行一個服務(wù)器,不然使用templateUrl會報錯 Cross Origin Request Script(CORS)錯誤
由于加載html模板是通過異步加載的,若加載大量的模板會拖慢網(wǎng)站的速度,這里有個技巧,就是先緩存模板
你可以再你的index頁面加載好的,將下列代碼作為你頁面的一部分包含在里面。
我是模板內(nèi)容
這里的id屬性就是被設(shè)置在templateUrl上用的。
另一種辦法緩存是:
angular.module("template.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("template.html",
"wo shi mu ban");
}]);
6.replace
(布爾值),默認(rèn)值為false,設(shè)置為true時候,我們再來看看下面的例子(對比下在template時候舉的例子)
angular.module("app",[]).directive("hello",function(){
return{ restrict:"EA", replace:true, template:"" }; })hello world
HTML代碼為:
渲染之后的代碼:
另外當(dāng)模板為純文本(即template:"wo shi wen ben")的時候,渲染之后的html代碼默認(rèn)的為文本用span包含。
7.scope
可選參數(shù),(布爾值或者對象)默認(rèn)值為false,可能取值:
(1)默認(rèn)值false。
表示繼承父作用域;
(2)true
表示繼承父作用域,并創(chuàng)建自己的作用域(子作用域);
(3){}
表示創(chuàng)建一個全新的隔離作用域;
7.1首先我們先來了解下scope的繼承機制。我們用ng-controller這個指令舉例,
我們都知道ng-controller(內(nèi)置指令)可以從父作用域中繼承并且創(chuàng)建一個新的子作用域。如下:
parentNode:父親
chrildNode: 兒子
若去掉
$scope.aaa = "兒子"
則顯示
parentNode:父親
chrildNode: 父親
注意:
1)若一個元素上有多個指令,使用了隔離作用域,則只有其中一個可以生效;
2)只有指令模板中的根元素才能獲得一個新的作用域,這時候,scope就被設(shè)置為true了;
parentNode:父親
chrildNode: cunjieliu
孫女
上面中class為one那個div獲得了指令ng-controller=’myController‘所創(chuàng)建的新的作用域;
而class為two那個div獲得了指令ng-controller=’myController2‘所創(chuàng)建的新的作用域;
這就是“只有指令模板中的根元素才能獲得一個新的作用域”;
接下來我們通過一個簡單明了的例子來說明scope取值不同的差別
依次設(shè)置scope的值false,true,{},結(jié)果發(fā)現(xiàn)(大家別偷懶,動手試試哈)
當(dāng)為false時候,兒子繼承父親的值,改變父親的值,兒子的值也隨之變化,反之亦如此。(繼承不隔離)
當(dāng)為true時候,兒子繼承父親的值,改變父親的值,兒子的值隨之變化,但是改變兒子的值,父親的值不變。(繼承隔離)
當(dāng)為{}時候,沒有繼承父親的值,所以兒子的值為空,改變?nèi)魏我环降闹稻荒苡绊懥硪环降闹?。(不繼承隔離)
tip:當(dāng)你想要創(chuàng)建一個可重用的組件時隔離作用域是一個很好的選擇,通過隔離作用域我們確保指令是‘獨立’的,并可以輕松地插入到任何HTML app中,并且這種做法防止了父作用域被污染;
7.2隔離作用域可以通過綁定策略來訪問父作用域的屬性。
下面看一個例子
運行代碼,并在input中輸入顏色值,結(jié)果為
你知道用AngularJs怎么定義指令嗎?2
但是,但我們將scope設(shè)置為{}時候,再次運行上面的代碼可以發(fā)現(xiàn)頁面并不能成功完整顯示!
原因在于,這里我們將scope設(shè)置為{},產(chǎn)生了隔離作用域。
所以在template模板中{{color}}變成了依賴于自己的作用域,而不是依賴于父作用域。
因此我們需要一些辦法來讓隔離作用域能讀取父作用域的屬性,就是綁定策略。
下面我們就來探索設(shè)置這種綁定的幾種方法
方法一:使用@(@attr)來進(jìn)行單向文本(字符串)綁定
這種辦法只能單向,通過在運行的指令的那個html標(biāo)簽上設(shè)置color-attr屬性,并且采用{{}}綁定某個模型值。
注意,你也可以再這里直接綁定字符串的顏色值,如:color-attr=“red”;
然后你可以看到表達(dá)式{{color}}被賦值給了color-attr。
當(dāng)表達(dá)式的值發(fā)生變化時,屬性color-attr也會發(fā)生變化,所以也改變了隔離作用域中的屬性color。
tips:如果綁定的隔離作用域?qū)傩悦c元素的屬性名相同,則可以采取缺省寫法。
html:
js定義指令的片段:
app.directive("helloWorld",function(){
return { scope: { color: "@" }, ... //配置的余下部分 }
});
方法二:使用=(=attr)進(jìn)行雙向綁定
此處也類似上面采用了缺省的寫法。
這里需要注意的是,我們要直接在指令運行的那個元素上設(shè)置屬性時候,是直接將 實際的作用域模型 賦值給該屬性(這里就是color)
這樣一個雙向綁定被建立了,改變?nèi)魏我粋€input都會改變另一個值。
你知道用AngularJs怎么定義指令嗎?3
方法三:使用&來調(diào)用父作用域中的函數(shù)
運行之后,彈出alert框。
8.transclude
(布爾值或者字符‘element’),默認(rèn)值為false;
這個配置選項可以讓我們提取包含在指令那個元素里面的內(nèi)容,再將它放置在指令模板的特定位置。
當(dāng)你開啟transclude后,你就可以使用ng-transclude來指明了應(yīng)該在什么地方放置transcluded內(nèi)容
運行上面的代碼,輸出
china
leifeng
另外當(dāng)開啟transclude,會創(chuàng)建一個新的transclude空間,并且繼承了父作用域(即使Scope設(shè)置為隔離作用域),
上面代碼中的{{name}}是依賴于父作用域的,仍然能被渲染出來,就說明了這點。
我們再看看生成的html為下圖所示,可以發(fā)現(xiàn)文本“你看不見我”消失了,這是因為被transclude內(nèi)容替換掉了。
這里的transclude內(nèi)容就是{{name}}
你知道用AngularJs怎么定義指令嗎?4
接下來再來看看transclude的另一個取值transclude:“element”
那transclude:“element”與transclude:true有什么區(qū)別呢?
區(qū)別在于嵌入的內(nèi)容,以上面的例子來說,
當(dāng)transclude:true時候,嵌入的內(nèi)容為{{name}},
而當(dāng)transclude:“element”時候,嵌入的內(nèi)容為
{{name}}
沒錯,此時嵌入的內(nèi)容為整個元素。
將上面代碼transclude:true換成transclude:true后,再運行,你會發(fā)現(xiàn)結(jié)果并不是和你想的一樣
再次查看生成的html代碼
你知道用AngularJs怎么定義指令嗎?5
你會發(fā)現(xiàn)指令綁定的元素被轉(zhuǎn)換為了一個HTML注釋
關(guān)于這方面的疑問可以查看 transclude: "element" is useless without replace:true 獲取更多
解決方案是加上replace: true,就正常了
這時再查看HTML代碼
你知道用AngularJs怎么定義指令嗎?6
注意:在一個指令的模板template上只能申明一個ng-transclude。
OK,那么現(xiàn)在問題來了,如果我們想把嵌入部分多次放入我們的模板中要怎么辦?
則可以使用$transclude(后面再controller選項中會講)
或者可以使用compile函數(shù),里面有個transcludeFn參數(shù)(后面會講)
或者使用link鏈接函數(shù)。。。
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等等)
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ù)(后面會講)可以進(jìn)行互換。區(qū)別在于,控制器主要是用來提供可在指令間復(fù)用的行為但link鏈接函數(shù)只能在當(dāng)前內(nèi)部指令中定義行為,且無法再指令間復(fù)用。
html代碼: }); 你知道用AngularJs怎么定義指令嗎?7 并且在控制臺下輸出hello everyone 讓我們看看$transclude();在這里,它可以接收兩個參數(shù),第一個是$scope,作用域,第二個是帶有參數(shù)clone的回調(diào)函數(shù)。 而這個clone實際上就是嵌入的內(nèi)容(經(jīng)過jquery包裝),可以在它上做很多DOM操作。 它還有最簡單的用法就是 }); 默認(rèn)情況下,如果我們簡單實用$transclude(),那么默認(rèn)的其作用域就是$transclude生成的作用域 但是如果我們實用$transclude($scope,function(clone){}),那么作用域就是directive的作用域了 那么問題又來了。如果我們想實用父作用域呢 可以使用$scope.$parent
運行上面的代碼就是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);
}
};
注意:使用$transclude會生成一個新的作用域。
var app = angular.module("myApp",[]); app.controller("sonctrl",function($scope){ $scope.title = "hello son"; }); app.controller("parentctrl",function($scope){ $scope.title = "hello parent"; }); app.directive("mySite", function () { return { restrict: "EA", transclude: true, controller: function ($scope, $element,$attrs,$transclude,$log) { var a = $transclude(); $element.append(a); $log.info($scope.title); $log.info($scope.$parent.title); } };
});
同理想要一個新的作用域也可以使用$scope.$parent.new();
10.controllerAs
這個選項的作用是可以設(shè)置你的控制器的別名
一般以前我們經(jīng)常用這樣方式來寫代碼:
angular.module("app",[])
.controller("demoController",["$scope",function($scope){
$scope.title = "angualr";
}])
{{title}}
angular.module("app",[])
.controller("demoController",[function(){
this.title = "angualr";
}])
{{demo.title}}
angular.module("myApp",[]).directive("mySite", function () { return { restrict: "EA", transclude: true, controller:"someController", controllerAs:"mainController" //..其他配置 };
});
11.require(字符串或者數(shù)組)
字符串代表另一個指令的名字,它將會作為link函數(shù)的第四個參數(shù)
具體用法我們可以舉個例子說明
假設(shè)現(xiàn)在我們要編寫兩個指令,兩個指令中的link鏈接函數(shù)中(link函數(shù)后面會講)存在有很多重合的方法,
這時候我們就可以將這些重復(fù)的方法寫在第三個指令的controller中(上面也講到controller經(jīng)常用來提供指令間的復(fù)用行為)
然后在這兩個指令中,require這個擁有controller字段的的指令(第三個指令),
最后通過link鏈接函數(shù)的第四個參數(shù)就可以引用這些重合的方法了。
上面例子中的指令innerDirective和指令innerDirective2復(fù)用了定義在指令outerDirective的controller中的方法
也進(jìn)一步說明了,指令中的controller是用來讓不同指令間通信用的。
另外我們可以在require的參數(shù)值加上下面的某個前綴,這會改變查找控制器的行為:
(1)沒有前綴,指令會在自身提供的控制器中進(jìn)行查找,如果找不到任何控制器,則會拋出一個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ù)進(jìn)行編譯,
angularjs會遍歷整個HTML文檔,并根據(jù)js中指令的定義來處理在頁面上聲明的各個指令
按照指令的優(yōu)先級(priority)排列,根據(jù)指令中的配置參數(shù)(template,place,transclude等)轉(zhuǎn)換DOM
然后就開始按順序執(zhí)行各指令的compile函數(shù)(如果指令上有定義compile函數(shù))對模板自身進(jìn)行轉(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.compile編譯函數(shù)和link鏈接函數(shù)
13.1compile編譯函數(shù)選項
compile選項可以返回一個對象或者函數(shù)
在這里我們可以在指令和實時數(shù)據(jù)被放到DOM中之前進(jìn)行DOM操作,
比如我們可以在這里進(jìn)行添加或者刪除節(jié)點的DOM的操作。
所以編譯函數(shù)是負(fù)責(zé)對模板的DOM進(jìn)行轉(zhuǎn)換,并且僅僅只會運行一次。
//compile函數(shù)的語法
compile:function compile(tElement,tAttrs,transclude){
return{ pre:function preLink(scope,iElement,iAttrs,controller){}, post:function postLink(scope,iElement,iAttrs,controller){} } }
對于我們編寫的大部分的指令來說,并不需要對模板進(jìn)行轉(zhuǎn)換,所以大部分情況只要編寫link函數(shù)就可以了。
tips:preLink函數(shù)會在編譯階段之后,指令鏈接到子元素之前執(zhí)行
類似的,postLink會在指令鏈接到子元素之后執(zhí)行 這意味著,為了不破壞綁定過程,如果你需要修改DOM結(jié)構(gòu),你應(yīng)該在postLink函數(shù)中來做這件事。
13.2link鏈接函數(shù)選項
鏈接函數(shù)負(fù)責(zé)將作用域和DOM進(jìn)行鏈接。
//link鏈接函數(shù)
link:function postLink(scope,iElement,iAttrs){}
若指令中定義有require選項,則link函數(shù)會有第四個參數(shù),代表控制器或者所依賴的指令的控制器(上面require選項例子已有例子)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/80424.html
摘要:系列種優(yōu)化頁面加載速度的方法隨筆分類中個最重要的技術(shù)點常用整理網(wǎng)頁性能管理詳解離線緩存簡介系列編寫高性能有趣的原生數(shù)組函數(shù)數(shù)據(jù)訪問性能優(yōu)化方案實現(xiàn)的大排序算法一怪對象常用方法函數(shù)收集數(shù)組的操作面向?qū)ο蠛驮屠^承中關(guān)鍵詞的優(yōu)雅解釋淺談系列 H5系列 10種優(yōu)化頁面加載速度的方法 隨筆分類 - HTML5 HTML5中40個最重要的技術(shù)點 常用meta整理 網(wǎng)頁性能管理詳解 HTML5 ...
摘要:系列種優(yōu)化頁面加載速度的方法隨筆分類中個最重要的技術(shù)點常用整理網(wǎng)頁性能管理詳解離線緩存簡介系列編寫高性能有趣的原生數(shù)組函數(shù)數(shù)據(jù)訪問性能優(yōu)化方案實現(xiàn)的大排序算法一怪對象常用方法函數(shù)收集數(shù)組的操作面向?qū)ο蠛驮屠^承中關(guān)鍵詞的優(yōu)雅解釋淺談系列 H5系列 10種優(yōu)化頁面加載速度的方法 隨筆分類 - HTML5 HTML5中40個最重要的技術(shù)點 常用meta整理 網(wǎng)頁性能管理詳解 HTML5 ...
摘要:尤其,對于組件化起了非常大的作用。今天就簡單介紹一下我的一個懶人組件百度地圖。后面詳細(xì)介紹該對象參數(shù)字符串,是你在百度開放平臺申請的,沒有這個,你的地圖顯示不出來的表達(dá)式,用來控制離線后的友好支持,后面詳細(xì)介紹各參數(shù)。 前言 AngularJS作為一個成功的框架,營造出了完備的生態(tài)系統(tǒng)。尤其Directive,對于組件化起了非常大的作用。很多時候,如我這般懶人,網(wǎng)上搜一搜,就找到一個合...
摘要:實例元素及實例屬性都會作為參數(shù)傳遞到函式函式關(guān)連於此實例的實例元素實例元素的屬性結(jié)論到目前為止,但愿你有清楚的理解關(guān)于及之間的差異。 原文地址:https://987.tw/2014/09/03/ang... AngularJS directives是令人驚艷的。它允許你創(chuàng)造高度語意且可重復(fù)利用的元件。在某種意義上你可以認(rèn)為它是極致的web components先驅(qū)者。 有許多很棒的文...
閱讀 3028·2023-04-25 18:00
閱讀 2237·2021-11-23 10:07
閱讀 4081·2021-11-22 09:34
閱讀 1256·2021-10-08 10:05
閱讀 1579·2019-08-30 15:55
閱讀 3449·2019-08-30 11:21
閱讀 3352·2019-08-29 13:01
閱讀 1391·2019-08-26 18:26