摘要:方法三使用調用父作用域中的函數(shù)實例地址同樣采用了缺省寫法,運行之后,彈出窗口布爾值或者字符,默認值為這個配置選項可以讓我們提取包含在指令那個元素里面的內(nèi)容,再將它放置在指令模板的特定位置。
準備代碼,會在實例中用到
var app = angular.module("app", []);
angular指令定義大致如下
app.directive("directiveName", function() { return { // config } })
其中return返回的配置對象包含很多參數(shù),如下一一說明。
1. restrict值為字符串,可選參數(shù),指明指令在DOM中以什么形式被聲明
默認值為restrict: "EA",表示可以在DOM里面可以用元素形式和屬性形式被聲明。一般來說,如果你想創(chuàng)建一個自己模板的組件時,則使用元素形式,但是僅僅是為已有元素添加功能的話,就使用屬性名。
2. priority如果想要支持IE8,則最好使用屬性和類形式來定義,另外從angular 1.3.X開始,已經(jīng)放棄支持IE8了。
數(shù)字,可選參數(shù),致命指令的優(yōu)先級,若在單個DOM元素上有多個指令,則優(yōu)先級高的先執(zhí)行。
當然,設置指令的優(yōu)先級不太常用,但是比較特殊的例子是,內(nèi)置指令ng-repeat的優(yōu)先級為1000,而ng-init的優(yōu)先級為 450。
3. terminal布爾型,可選參數(shù),可以被設置為true或者false,若設置為true,則優(yōu)先級低于此指令的其他指令則無效,不會被調用優(yōu)先級相同任然會執(zhí)行。
4. template字符串或者函數(shù),可選參數(shù)。
可以是一段html文本
app.directive("hello", function() { return { template: "" } })Hello, world!
使用如下
渲染結果為
Hello, world!
也可以是一個函數(shù),可接受兩個參數(shù)Element與Attrs
其中Element是指使用此指令的元素,而Attrs則是實例的屬性,它是由一個元素上所有屬性組成的集合,形如
{ title: "test", id: "testDiv", class: "demo", input: "text", ... }
下面讓我們看看template是一個函數(shù)時的情況
app.directive("hello", function() { return { template: function(element, attrs) { return ""+ attrs.title +"" } }; });
html代碼
渲染結果
message
實例地址
5. replace布爾型,默認值為false,設置為true的時候,表示可以用模板內(nèi)容替換自定義的元素標簽。
在template的例子中,我們發(fā)現(xiàn)渲染結果中包含有自定義的元素
app.directive("hello", function() { return { replace: true, template: function(element, attrs) { return ""+ attrs.title +"" } }; });
渲染結果如下,hello標簽消失不見
6. templateUrlmessage
字符串或者函數(shù),可選參數(shù)
可以使一個代表html文件路徑的字符串,也可以是一個函數(shù),大致意思與template一樣。
在本地開發(fā)時,需要運行一個服務器,不然使用templateUrl會報錯
Cross origin request script(cors)
由于加載html模板是通過異步加載,若加載大量的模板會拖慢網(wǎng)站的速度,這里有一個技巧,就是先緩存模板,你可以先在你的index頁面加載好,將下列代碼作為你頁面的一部分包含在內(nèi)
這里的id屬性就是被設置在templateUrl上用的
另外一種方法緩存如下
app.run(function($templateCache) { $templateCache.put("template.html", "7. scopetemplate"); })
布爾值或者對象,可選參數(shù),默認值為false,表示繼承父級作用域。
如果值為true,表示繼承父作用域,并創(chuàng)建自己的作用域(子作用域)
如果為對象,{},則表示創(chuàng)建一個全新的隔離作用域。
首先我們需要來了解一下scope的繼承機制。我們使用ng-controller這個指令來舉例。我們都知道ng-controller可以從父作用域中繼承并創(chuàng)建一個新的子作用域。如下:
parentNode: {{aaa}}childrenNode: {{aaa}}
angular.module("app", []) .controller("demoController", function($scope) { $scope.aaa = "children"; })
實例地址
這時頁面的顯示結果為
parentNode: parent childrenNode: children
當時當我們并沒有在demoController的作用域中給aaa賦值,也就是在上例中刪除這一句$scope.aaa = "children";,那么執(zhí)行結果就為
parentNode: parent childrenNode: parent
注意:如果一個元素上有多個指令都使用了隔離作用域,那么只有其中一個可以生效,只有指令模板中的根元素才能獲得一個新的作用域,這時候,scope就被設置為true了。
parentNode: {{aaa}}childrenNode: {{aaa}}lastNode: {{aaa}}
angular.module("app", []) .controller("demoController01", function($scope) { $scope.aaa = "children"; }) .controller("demoController02", function($scope) { $scope.aaa = "last" })
實例地址
接下來,我們通過一個簡單明了的例子來說明scope取值的不同差別
parent: {{ name }}
angular.module("app", []) .controller("mainController", function($scope) { $scope.name = "Jake"; }) .directive("myDirective", function() { return { restrict: "EA", scope: false, replace: true, template: "" + "" + "childNode: {{ name }} " + "" } })
" + "" + "
實例地址
點擊上面的實例地址,我們可以依次改變scope的值為false, true, {},結果發(fā)現(xiàn)
false:兒子繼承父親的值,改變父親的值,兒子的值也隨著改變,反之亦然,這就是繼承且不隔離
true:兒子繼承父親的值,改變父親的值,兒子的值也隨著改變,但是改變兒子的值,父親的值并沒有改變,這就是繼承但是隔離
{}:沒有繼承父親的值,所以兒子的值為空,改變?nèi)魏我环降闹刀疾粫绊懥硪环?,這就是不繼承且隔離
當想要創(chuàng)建一個可重用的組件時,隔離作用域是一個很好的選擇,通過隔離作用域,我們可以確保指令是獨立的,并且可以輕松的插入到任何HTML APP中,并且這種做法防止了父作用域被污染。
隔離作用域可以通過綁定策略來訪問父作用域的屬性
我們來看一個例子
angular.module("app", []) .controller("mainController", function($scope) { }) .directive("helloWorld", function() { return { restrict: "EA", scope: false, replace: true, template: "Hello world!
" } })
運行上面的代碼,我們在input中輸入顏色值,比如red,那么hello world一行的背景就會變成紅色。動手試試!
實例地址
但是,當我們將scope的值設置為{}時,再次運行代碼就發(fā)現(xiàn)頁面并不能成功的完整顯示了.這是因為{}讓helloWorld指令產(chǎn)生了隔離作用域,沒辦法從父級作用域中繼承到color的值了。
所以在template中的{{color}}變成了依賴于自己的作用域,而不是依賴于父級作用域。因此我們需要一些辦法來讓隔離作用域能夠讀取父級作用域的屬性,這個方法就是綁定策略。
下面我們來探索設置這種綁定策略的幾種方法
angular.module("app", []) .controller("mainController", function($scope) { }) .directive("helloWorld", function() { return { restrict: "EA", scope: { color: "@colorAttr" }, replace: true, template: "Hello world!
" } })
實例地址
這種辦法只能單向,通過在運行的指令DOM上設置color-attr屬性,并且采用{{}}綁定某個模型值。當然,我們也可以直接在這里綁定字符串的顏色值,如color-attr="red"
因此當表達式的值發(fā)生變化時,屬性color-attr的值也會發(fā)生變化,通過單向綁定該值,就可以改變隔離作用域中的屬性color.
如果綁定的隔離作用域屬性名與元素的屬性名相同,則可以采用缺省寫法
// html// js app.directive("helloWorld", function() { return { scope: { color: "@" }, ... } })
{{ color }}
angular.module("app", []) .controller("mainController", function($scope) { $scope.color = "red"; }) .directive("helloWorld", function() { return { restrict: "EA", scope: { color: "=" }, replace: true, template: "" } })" + "Hello world!" + "
" + "
實例地址
此處也采用了類似的缺省寫法。
這里需要注意的是,我們要直接在指令元素設置屬性時,是直接將實際的作用域模型復制給該屬性
這樣一個雙向綁定被建立了,改變?nèi)魏我粋€input值都會改變另外一個值。
{{ name }}
angular.module("app", []) .controller("mainController", function($scope) { $scope.name = "yangbo"; $scope.say = function() { alert("hello!"); } }) .directive("helloWorld", function() { return { restrict: "EA", scope: { name: "@", say: "&" }, replace: true, template: "" } })
實例地址
同樣采用了缺省寫法,運行之后,彈出窗口!
8. transclude布爾值或者字符element,默認值為false
這個配置選項可以讓我們提取包含在指令那個元素里面的內(nèi)容,再將它放置在指令模板的特定位置。當我們開啟transclude之后,我們就可以使用ng-transclude來指明應該在什么地方放置transclude的內(nèi)容
china
{{name}}
angular.module("app", []) .controller("mainController", function($scope) { $scope.name = "yangbo5207"; }) .directive("helloWorld", function() { return { restrict: "EA", scope: {}, replace: true, transclude: true, template: "" } })你看不見我
運行上面的代碼,輸出
china yangbo5207
我們查看渲染出來的html,結果為
china
yangbo5207
另外當開啟transclude時,會創(chuàng)建一個新的transclude空間,并且繼承父作用域(也就是scope設置的隔離作用域)
從上面例子我們知道,當transclude的值被設置為true時,嵌入的內(nèi)容為{{name}},但是如果將它的值設置為element呢,我們可以在上例的基礎上進行一個簡單的修改,發(fā)現(xiàn),嵌入內(nèi)容為整個元素
{{name}}
查看渲染結果
china
yangbo5207
注意:在一個指令的模板中,只能聲明一次ng-transclude
那么問題來了,如果我們想要把嵌入內(nèi)容多次放入我們的模板中怎么辦?
可以使用$transclude,后面會講到!也可以使用complie函數(shù)中,里面的transcludeFn參數(shù),后面會講到!或者使用link連接函數(shù)
9. controller可以是一個字符串或者函數(shù)。
若為字符串,則將字符串當做控制器的名字,來查找注冊在應用中的控制器的構造函數(shù)
angular.module("app", []) .directive("myDirective", function() { return { restrict: "EA", replace: true, transclude: true, // 會查找模塊中其他被名為targetController的控制器 controller: "targetController" } }) .controller("targetController", function($scope, $element, $attrs, $transclude) { // 控制器邏輯放在這里 })
當然,也可以直接在指令內(nèi)部定義為匿名函數(shù),同樣可以注入任何服務
angular.module("app", []) .directive("myDirective", function() { return { restrict: "EA", replace: true, transclude: true, controller: function($scope, $element, $attrs, $transclude) { // 控制器邏輯 } } })
另外還有一些特殊的服務可以注入,
$scope 與指令元素相關聯(lián)的作用域
$element 當前指令對應的元素
$attrs 當前元素的屬性組成的對象
$transclude 嵌入鏈接函數(shù),實際被執(zhí)行用來克隆元素和操作DOM中的函數(shù)(除非是用來定義一些可復用的行為,否則一般不推薦在這使用)
指令的控制器和link函數(shù)(后面會講到)可以進行互換。區(qū)別在于,控制器主要用來提供可在指令間復用的行為,可對外提供與外部交互的接口,但是link鏈接只能在當前指令內(nèi)部中定義行為,且無法在指令間復用。
外面的世界很精彩。
angular.module("app", []) .directive("testDirective", function() { return { transclude: true, replace: true, controller: function($scope, $element, $attrs, $transclude, $log) { $transclude(function(clone) { var a = angular.element(""); a.attr("href", $attrs.url); a.text(clone.text()); $element.append(a); }); } } })
實例地址
$transclude 可以接受兩個參數(shù),第一個是$scope,第二個是才有參數(shù)clone的回調函數(shù)。
而這個clone實際上就是嵌入的內(nèi)容。可以在根據(jù)它做很多DOM操作。
它還有最簡單的用法
angular.module("app", []) .directive("testDirective", function() { return { transclude: true, replace: true, controller: function($scope, $element, $attrs, $transclude, $log) { // 這里的$transclude就是嵌入的內(nèi)容 var a = $transclude(); $element.append(a); } } })
但是我們要注意,使用$transclude會生成一個新的作用域。默認情況下,如果我們簡單使用$transclude(),那么其作用域就是$transclude 生成的作用域。但是如果我們使用$transclude($scope, function(clone) {}),那么作用域就是directive的作用域了。
當然問題又來了,如果我們想使用父級作用域呢?
$scope.$parent
炒美股,上老虎2
angular.module("app", []) .controller("parentController", function($scope) { $scope.title = "PARENT TIGER"; }) .controller("sonController", function($scope) { $scope.title = "CHILDREN TIGER"; }) .directive("testDirective", function() { return { transclude: true, replace: true, controller: function($scope, $element, $attrs, $transclude, $log) { var a = $transclude(); $element.append(a); $log.info($scope.title); $log.info($scope.$parent.title); } } })
實例地址
10. controllerAsangualr 1.2之后,就已經(jīng)開始支持controllerAs的語法,這樣我們就可以不用將屬性和方法掛載到$scope上,而是this上。
{{ demo.name }}
angular.module("app", []) .controller("demoController", function() { this.name = "Jake"; })
實例地址
我們可以從實例中看出,這里的this就是指的as后面的那個別名。然后我們在表達式中就可以使用這個別名
我們知道,在directive中的controller,主要職能是對外提供交互接口,而結合require與link,因此我們常常會利用這樣的語法而非上面例子中的$scope
app.directive("testDirective", function() { return { controller: function() { this.name = "Jake"; } } })11. require
字符串或者數(shù)組,字符串代表另一個指令的名字,它將作為link函數(shù)的第四個參數(shù)。具體用法我們可以舉例子來說明。
假設現(xiàn)在我們要編寫兩個指令,兩個指令的link函數(shù)中存在許多重合的方法,這時候我們就可以將這些重復的方法寫在第三個指令的controller中,然后在這兩個指令中,使用require將第三個指令引入進來,然后我們就可以通過link連接函數(shù)的第四個參數(shù)引用這些重合的方法了
指令之間常常通過這種方式進行交互
{{expander.text}}
var expModule=angular.module("expanderModule",[]) expModule.directive("accordion", function() { return { restrict : "EA", replace : true, transclude : true, template : "", controller : function() { var expanders = []; this.gotOpened = function(selectedExpander) { angular.forEach(expanders, function(expander) { if (selectedExpander != expander) { expander.showMe = false; } }); } this.addExpander = function(expander) { expanders.push(expander); } } } }); expModule.directive("expander", function() { return { restrict : "EA", replace : true, transclude : true, require : "^?accordion", scope : { title : "=expanderTitle" }, template : "" + "", link : function(scope, element, attrs, accordionController) { scope.showMe = false; accordionController.addExpander(scope); scope.toggle = function toggle() { scope.showMe = !scope.showMe; accordionController.gotOpened(scope); } } } }); expModule.controller("SomeController",function($scope) { $scope.expanders = [{ title : "Click me to expand", text : "Hi there folks, I am the content that was hidden but is now shown." }, { title : "Click this", text : "I am even better text than you have seen previously" }, { title : "Test", text : "test" }]; });{{title}}" + "" + "
實例地址
實例說明,controller是用來與不同指令之間通信的。
另外我們可以在require的參數(shù)值加上下面的某個前綴,這回改變查找控制器的行為。
沒有前綴 指令會在自身提供的控制器中進行查找,如果找不到任何控制器,則會拋出一個error
? 若在當前指令中沒有找到所需的控制器,則會將null傳給link鏈接函數(shù)的第四個參數(shù)
^ 如果在當前的指令中沒有找到所需的控制器,則會查找父元素的控制器
?^ 如果在當前和父元素中都沒有找到控制器,則會將null傳給link
12. angular指令編譯過程首先加載angular庫,查找ng-app指令,從而找到應用的邊界,根據(jù)ng-app劃定的作用域來調用$compile服務進行編譯。
angular會遍歷整個html文檔,并根據(jù)js中指令的定義來處理在頁面上聲明的各個指令,按照指令的優(yōu)先級排列,根據(jù)指令中的配置參數(shù)(template, replace, transclude等)轉換DOM,然后就開始按照順序執(zhí)行各指令的compile函數(shù)(如果指令上有定義compile函數(shù))對模板自身進行轉換。
此處的compile函數(shù)值什么指令中配置的,與上面說的$compile服務不一樣
每個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ù)就會運行,她做的事情大致跟上面compile返回之后所有的link合成的大link函數(shù)差不多。
所以,在指令中compile與link選項是互斥的,如果同時設置了這兩項,那么就會把compile所返回的函數(shù)當做是鏈接函數(shù),而link選項本身會被忽略。
13. compile編譯函數(shù)與link鏈接函數(shù)cmopile選項可以返回一個對象或者函數(shù),在這里我們可以在指令和實時數(shù)據(jù)被放到DOM之前進行DOM操作,比如我們可以在這里進行添加或者刪除節(jié)點的DOM操作。
所以編譯函數(shù)是負責對模板的DOM進行轉換,并且僅僅只會運行一次
//compile函數(shù)的語法 compile:function compile(tElement,tAttrs,transclude){ return{ pre:function preLink(scope,iElement,iAttrs,controller){}, post:function postLink(scope,iElement,iAttrs,controller){} } }
對于我們編寫的大部分指令來說,并不需要對模板進行轉換,所以大部分情況只需要編寫link函數(shù)就行。
preLink函數(shù)會在編譯階段之后,指令鏈接到子元素之前執(zhí)行,類似的,postLink會在指令鏈接到子元素之后執(zhí)行。這意味著,為了不破壞綁定過程,如果你需要修改DOM結構,你應該在postLink函數(shù)中來做這件事情。
link函數(shù)負責將作用域與DOM進行鏈接
//link鏈接函數(shù) link:function postLink(scope,iElement,iAttrs){}
若指令中定義有require選項,則link函數(shù)會有第四個參數(shù),代表控制器或者所依賴的指令的控制器(上面require選項例子已有例子)
內(nèi)容都真夠多的,終于整理完了,今天寫了兩篇文章,感覺好累!如果大家覺得文章對你有幫助,求贊求收藏。
許多內(nèi)容都是從不同的網(wǎng)站上整理而來,每一個實例都是自己運行過后保存在codepen上,大家可以結合codepen的例子結合理解文章內(nèi)容,本文屬于收集文,非原創(chuàng),但絕對干貨!值!得!一!贊!與收藏。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79838.html
摘要:方法三使用調用父作用域中的函數(shù)實例地址同樣采用了缺省寫法,運行之后,彈出窗口布爾值或者字符,默認值為這個配置選項可以讓我們提取包含在指令那個元素里面的內(nèi)容,再將它放置在指令模板的特定位置。 準備代碼,會在實例中用到 var app = angular.module(app, []); angular指令定義大致如下 app.directive(directiveName, functi...
摘要:方法三使用調用父作用域中的函數(shù)實例地址同樣采用了缺省寫法,運行之后,彈出窗口布爾值或者字符,默認值為這個配置選項可以讓我們提取包含在指令那個元素里面的內(nèi)容,再將它放置在指令模板的特定位置。 準備代碼,會在實例中用到 var app = angular.module(app, []); angular指令定義大致如下 app.directive(directiveName, functi...
摘要:實例元素及實例屬性都會作為參數(shù)傳遞到函式函式關連於此實例的實例元素實例元素的屬性結論到目前為止,但愿你有清楚的理解關于及之間的差異。 原文地址:https://987.tw/2014/09/03/ang... AngularJS directives是令人驚艷的。它允許你創(chuàng)造高度語意且可重復利用的元件。在某種意義上你可以認為它是極致的web components先驅者。 有許多很棒的文...
摘要:可選參數(shù),布爾值或者對象默認值為,可能取值默認值。布爾值或者字符,默認值為這個配置選項可以讓我們提取包含在指令那個元素里面的內(nèi)容,再將它放置在指令模板的特定位置。 前言 最近學習了下angularjs指令的相關知識,也參考了前人的一些文章,在此總結下。 歡迎批評指出錯誤的地方。 Angularjs指令定義的API showImg(https://segmentfault.com/img...
閱讀 2418·2023-04-26 00:46
閱讀 581·2023-04-25 21:36
閱讀 729·2021-11-24 10:19
閱讀 2266·2021-11-23 09:51
閱讀 1015·2021-10-21 09:39
閱讀 830·2021-09-22 10:02
閱讀 1664·2021-09-03 10:29
閱讀 2677·2019-08-30 15:53