如何理解angular自定義指令directive的scope屬性?
目錄
1.背景介紹
2.知識(shí)剖析
3.常見問(wèn)題
4.解決方案
5.編碼實(shí)戰(zhàn)
6.擴(kuò)展思考
7.參考文獻(xiàn)
8.更多討論
1.背景介紹
指令定義
AngularJS與JQuery最大的區(qū)別表現(xiàn)在數(shù)據(jù)雙向綁定,實(shí)質(zhì)就是DOM的操作形式不一樣浑测。
? ? ? ? ? ? ? ? ? ? JQuery通過(guò)選擇器找到DOM元素杠输,再賦予元素的行為赎败;
? ? ? ? ? ? ? ? ? ? 而AngularJS則是,將指令與DOM綁定在一起蠢甲,再擴(kuò)展指令的行為僵刮。
? ? ? ? ? ? ? ? ? ? 例如, ng-click 可以讓一個(gè)元素能夠監(jiān)聽 click 事件鹦牛,并在接收到事件的時(shí)候執(zhí)行AngularJS表 達(dá)式搞糕。
? ? ? ? ? ? ? ? ? ? 我們可以自己創(chuàng)造新的指令。使用angular的directive( )這個(gè)模塊是用來(lái)定義指令的曼追。
2.知識(shí)剖析
一個(gè)完整的自定義指令所包含的內(nèi)容
angular.module(...);
? ? ? .directive('My-directive', function(injectables){
? ? ? ? restrict: 'A',
? ? priority: 0,
? ? template: '<div></div>',
? ? templateUrl: 'directive.html',
? ? replace: false,
? ? transclude: false,
? ? scope: false,
? ? compile: function(tElement, tAttrs, transclude){
? ? return{
? ? pre:function preLink(scope, iElement, iAttrs, controller){ ... },
? ? post:function postLink(scope, iElement, iAttrs, controller){ ... }
? ? }
? ? },
? ? link: function(scope, iElement, iAttrs){ ... }
});
restrict(字符串)
restrict 是一個(gè)可選的參數(shù)寞宫。它告訴AngularJS這個(gè)指令在DOM中可以何種形式被聲明。默 認(rèn)AngularJS認(rèn)為 restrict 的值是 A 拉鹃,即以屬性的形式來(lái)進(jìn)行聲明辈赋。
restrict 值可以是以下幾種:
E 作為元素名使用
A 作為屬性使用
C 作為類名使用
M 作為注釋使用
template (字符串或函數(shù))
template 參數(shù)是可選的,必須被設(shè)置為以下兩種形式之一:
? 一段HTML文本膏燕;
? 一個(gè)可以接受兩個(gè)參數(shù)的函數(shù)钥屈,參數(shù)為 tElement 和 tAttrs ,并返回一個(gè)代表模板的字符 串坝辫。
templateUrl篷就,引入外部的一個(gè)html文件
指令中的SCOPE
? ? ? ? ? ? ? ? directive 默認(rèn)能共享父 scope 中定義的屬性,例如在模版中直接使用父 scope 中的對(duì)象和屬性近忙。
? ? ? ? ? ? ? ? 通常使用這種直接共享的方式可以實(shí)現(xiàn)一些簡(jiǎn)單的 directive 功能竭业。但是當(dāng)要?jiǎng)?chuàng)建一個(gè)可以重復(fù)使用的
? ? ? ? ? ? ? ? directive的時(shí)候, 就不能依賴于父scope了及舍,因?yàn)樵诓煌牡胤绞褂胐irective對(duì)應(yīng)的父scope不一樣未辆。
? ? ? ? ? ? ? ? 所以需要一個(gè)隔離的scope。
2.2 scope屬性的3種取值
①锯玛、false(默認(rèn)值):直接使用父scope咐柜。
②、true:繼承父scope
③攘残、對(duì)象{ }:創(chuàng)建一個(gè)新的“隔離”scope拙友,但仍可與父scope通信。隔離的scope歼郭,通常用于創(chuàng)建可復(fù)用的指令遗契,也就是它不用管父scope中的model。然而雖然說(shuō)是“隔離”病曾,但通常我們還是需要讓這個(gè)子scope跟父scope中的變量進(jìn)行綁定牍蜂。綁定的策略有3種:@漾根、=、&捷兰。
@ 這是一個(gè)單項(xiàng)綁定的前綴標(biāo)識(shí)符
使用方法:在元素中使用屬性立叛,好比這樣 my-name="{{name}}",注意贡茅,屬性的名字要用-將兩個(gè)單詞連接秘蛇,因?yàn)槭菙?shù)據(jù)的單項(xiàng)綁定所以要通過(guò)使用{{}}來(lái)綁定數(shù)據(jù)。
= 這是一個(gè)雙向數(shù)據(jù)綁定前綴標(biāo)識(shí)符
使用方法:在元素中使用屬性顶考,好比這樣 my-age="age",注意赁还,數(shù)據(jù)的雙向綁定要通過(guò)=前綴標(biāo)識(shí)符實(shí)現(xiàn),所以不可以使用{{}}驹沿。
& 這是一個(gè)綁定函數(shù)方法的前綴標(biāo)識(shí)符
使用方法:在元素中使用屬性艘策,好比這樣 my-change="changeAge()",注意渊季,屬性的名字要用-將多個(gè)個(gè)單詞連接朋蔫。
指令中的 CONTROLLER , COMPILE , LINK函數(shù)
AngularJs 的生命周期;分為兩個(gè)階段:
第一個(gè)階段是編譯階段: 在編譯階段,AngularJS會(huì)遍歷整個(gè)HTML文檔并根據(jù)JavaScript中的指令定義來(lái)處理頁(yè)面上聲明的指令却汉。
? ? ? ? ? ? ? ? ? 每一個(gè)指令的模板中都可能含 有另外一個(gè)指令驯妄,另外一個(gè)指令也可能會(huì)有自己的模板。當(dāng)AngularJS調(diào)用HTML文檔根部的指令時(shí)合砂,
? ? ? ? ? ? ? ? ? 會(huì)遍歷其中所有的模板青扔,模板中也可能包 含帶有模板的指令.一旦對(duì)指令和其中的子模板進(jìn)行遍歷或編譯,
? ? ? ? ? ? ? ? ? 編譯后的模板會(huì)返回一個(gè)叫做模板函數(shù)的函數(shù)翩伪。我們有機(jī)會(huì)在指令的模板函 數(shù)被返回前微猖,對(duì)編譯后的DOM樹進(jìn)行修改。
第二個(gè)階段是鏈接階段:鏈接函數(shù)來(lái)將模板與作用域鏈接起來(lái);負(fù)責(zé)設(shè)置事件監(jiān)聽器缘屹,監(jiān)視數(shù)據(jù)變化和實(shí)時(shí)的操作DOM.鏈接函數(shù)是可選的凛剥。
如果定義了編譯函數(shù),它會(huì)返回鏈接函數(shù)囊颅,因此當(dāng)兩個(gè)函數(shù)都定義了時(shí)当悔,編譯函數(shù)會(huì)重載鏈接函數(shù)
? ? ? ? ? ? ? ? 指令的控制器和link函數(shù)可以進(jìn)行互換√叽控制器主要是用來(lái)提供可在指令間復(fù)用的行為,但鏈接函數(shù)只能在當(dāng)前內(nèi)部指令中定義行為嗅骄,
? ? ? ? ? ? ? ? 且無(wú)法在指令間復(fù)用.link函數(shù)可以將指令互相隔離開來(lái)胳挎,而controller則定義可復(fù)用的行為。
3.常見問(wèn)題
scope屬性的3種取值對(duì)指令有什么影響?
4.解決方案
每當(dāng)一個(gè)指令被創(chuàng)建的時(shí)候溺森,都會(huì)有這樣一個(gè)選擇慕爬,是繼承自己的父作用域(一般是外部的Controller提供的作用域或者根作用域($rootScope))窑眯,還是創(chuàng)建一個(gè)新的自己的作用域,當(dāng)然AngularJS為我們指令的scope參數(shù)提供了三種選擇医窿,分別是:false,true,{}磅甩;默認(rèn)情況下是false。
當(dāng)scope參數(shù)被設(shè)置為false時(shí)有什么情況發(fā)生在這種情況下姥卢,在指令模板中可以直接使用父作用域中的變量卷要,函數(shù)
<div ng-controller="MyCtrl"class="div1">
? ? ? ? ? ? ? ? ? ? Ctrl:<br>
? ? ? ? ? ? ? ? ? ? <input ng-model="userName">{{userName}}<br>
? ? ? ? ? ? ? ? ? ? Directive:<br>
? ? ? ? ? ? ? ? ? ? <hello></hello>
? ? ? ? ? ? ? ? ? ? ? ? 兄弟<br>
? ? ? ? ? ? ? ? ? ? <hello></hello>
? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? angular.module("app",[])
? ? ? ? ? ? //測(cè)試true和false
.controller("MyCtrl",function($scope){
? ? ? ? ? ? ? ? ? ? ? ? ? ? $scope.userName="山水";
})
? ? ? ? ? ? ? ? ? ? ? ? .directive("hello",function() {
return{
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? restrict:"AECM",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? template:'<div><input type="text" ng-model="userName">{{userName}}</div>',
replace:true,
scope:false? ? ? ? ? ? ? }
})
因?yàn)槲覀儗cope的屬性設(shè)置為false所以,我們創(chuàng)建的指令繼承了父作用域的一切屬性和方法独榴,這也使得在指令的模板中我們可以使用這些屬性和方法僧叉。
注意:此時(shí)我們?cè)谳斎肟蚶锔淖兠郑瑫?huì)發(fā)現(xiàn)上面的兩個(gè)名字都發(fā)生了變化
4.2 scope = true棺榔。
當(dāng)把scope屬性設(shè)置為true時(shí)瓶堕,這表明我們創(chuàng)建的指令要?jiǎng)?chuàng)建一個(gè)新的作用域,這個(gè)作用域繼承自我們的父作用域症歇。
修改上面的JS代碼郎笆,將指令中的:scope:false修改為scope:true "
然后我們?cè)僭囍谖覀兊膇nput輸入框中寫一些字符串,會(huì)發(fā)現(xiàn)忘晤,指令中的那個(gè)name發(fā)生了變化宛蚓,但是指令外的那個(gè)name卻沒(méi)有發(fā)生變化,這說(shuō)明了一個(gè)問(wèn)題德频。
當(dāng)我們將scope設(shè)置為true的時(shí)候苍息,我們就新創(chuàng)建了一個(gè)作用域,只不過(guò)這個(gè)作用域是繼承了我們的父作用域壹置;我覺得可以這樣理解竞思,我們新創(chuàng)建的作用域是一個(gè)新的作用域,只不過(guò)在初始化的時(shí)候钞护,用了父作用域的屬性和方法去填充我們這個(gè)新的作用域盖喷。它和父作用域不是同一個(gè)作用域。
當(dāng)我們將scope設(shè)置為false的時(shí)候,我們創(chuàng)建的指令和父作用域(其實(shí)是同一個(gè)作用域)共享同一個(gè)model模型难咕,所以在指令中修改模型數(shù)據(jù)课梳,它會(huì)反映到父作用域的模型中。
4.3 scope = {}
當(dāng)我們將scope的屬性設(shè)置為{}時(shí)余佃,我們可以做更多的事情暮刃。
AngularJS最強(qiáng)的大的地方之一就是它可以構(gòu)建組件,無(wú)論放在哪里都是可以使用的爆土;這所以可以做到這些椭懊,不得不歸功于指令的這個(gè)屬性;當(dāng)我們將scope設(shè)置為{}時(shí)步势,意味著我們創(chuàng)建的一個(gè)新的與父作用域隔離的新的作用域氧猬,這使我們?cè)诓恢劳獠凯h(huán)境的情況下背犯,就可以正常工作,不依賴外部環(huán)境盅抚。
我們使用了隔離的作用域漠魏,不代表我們不可以使用父作用域的屬性和方法。
我們可以通過(guò)向scope的{}中傳入特殊的前綴標(biāo)識(shí)符(即prefix)妄均,來(lái)進(jìn)行數(shù)據(jù)的綁定柱锹。
在創(chuàng)建了隔離的作用域,我們可以通過(guò)@,&,=引用應(yīng)用指令的元素的屬性
下面我們來(lái)看看如何使用這些前綴標(biāo)識(shí)符:
1.@:?jiǎn)蜗蚪壎ù曰蓿獠縮cope能夠影響內(nèi)部scope奕纫,但反過(guò)來(lái)不成立;
這是一個(gè)單項(xiàng)綁定的前綴標(biāo)識(shí)符烫沙。使用方法:在元素中使用屬性匹层,好比這樣? ? ? ? ? ??
<div my-directive="" my-name="{{name}}"></div>
注意,屬性的名字要用-將兩個(gè)單詞連接锌蓄,因?yàn)槭菙?shù)據(jù)的單項(xiàng)綁定所以要通過(guò)使用{{}}來(lái)綁定數(shù)據(jù)升筏。
2、=:雙向綁定瘸爽,外部scope和內(nèi)部scope的model能夠相互改變您访;
這是一個(gè)雙向數(shù)據(jù)綁定前綴標(biāo)識(shí)符。使用方法:在元素中使用屬性剪决,好比這樣? ? ? ? ? ? ? ?
<div my-directive="" my-name="name"></div>
注意灵汪,數(shù)據(jù)的雙向綁定要通過(guò)=前綴標(biāo)識(shí)符實(shí)現(xiàn),所以不可以使用{{}}柑潦。
3享言、&:把內(nèi)部scope的函數(shù)的返回值和外部scope的任何屬性綁定起來(lái)。
這是一個(gè)綁定函數(shù)方法的前綴標(biāo)識(shí)符渗鬼。使用方法:在元素中使用屬性览露,好比這樣
<div test-directive=""action="click()"></div>
注意,屬性的名字要用-將多個(gè)個(gè)單詞連接譬胎。
5.編碼實(shí)戰(zhàn)
6.擴(kuò)展思考
我們的指令是如何利用這些前綴標(biāo)識(shí)符來(lái)尋找我們想要的屬性或者函數(shù)的差牛?
@ 當(dāng)指令編譯到模板的name時(shí),就會(huì)到scope中尋找是否含有name的鍵值對(duì)堰乔,如果存在偏化,就像上面那樣,看到@就知道這是一個(gè)單向的數(shù)據(jù)綁定镐侯,然后尋找原來(lái)的那個(gè)使用指令的元素上(或者是指令元素本身)含有這個(gè)值的屬性即my-name={{name}}夹孔,然后在父作用域查找{{name}}的值,得到之后傳遞給模板中的name析孽。
=和&與@差不多搭伤,只不過(guò)=進(jìn)行的是雙向的數(shù)據(jù)綁定,不論模板還是父作用域上的屬性的值發(fā)生改變都會(huì)使另一個(gè)值發(fā)生改變袜瞬,而&是綁定函數(shù)而已怜俐。
7.參考文獻(xiàn)
參考一:AngularJS 自定義指令
參考二:一招制敵 - 玩轉(zhuǎn) AngularJS 指令的 Scope (作用域)
8.更多討論
鳴謝
感謝大家觀看
今天的分享就到這里啦,歡迎大家點(diǎn)贊邓尤、轉(zhuǎn)發(fā)拍鲤、留言、拍磚~
技能樹.IT修真院???
? “我們相信人人都可以成為一個(gè)工程師汞扎,現(xiàn)在開始季稳,找個(gè)師兄,帶你入門澈魄,掌控自己學(xué)習(xí)的節(jié)奏景鼠,學(xué)習(xí)的路上不再迷茫”痹扇。
? ?這里是技能樹.IT修真院铛漓,成千上萬(wàn)的師兄在這里找到了自己的學(xué)習(xí)路線,學(xué)習(xí)透明化鲫构,成長(zhǎng)可見化浓恶,師兄1對(duì)1免費(fèi)指導(dǎo)。
? ?快來(lái)與我一起學(xué)習(xí)吧~http://www.jnshu.com/login/1/21109035