如何理解ANGULAR自定義指令DIRECTIVE的SCOPE屬性?

如何理解angular自定義指令directive的scope屬性?

大家好,我是IT修真院鄭州分院第6期的學(xué)員王棟,一枚正直、純潔、善良的前端程序員今天給大家分享一下,修真院官網(wǎng)js任務(wù)八深度思考中的知識點——如何理解ANGULAR自定義指令DIRECTIVE的SCOPE屬性?

1.背景介紹

指令定義

AngularJS與JQuery最大的區(qū)別表現(xiàn)在數(shù)據(jù)雙向綁定,實質(zhì)就是DOM的操作形式不一樣。

JQuery通過選擇器找到DOM元素,再賦予元素的行為;

而AngularJS則是,將指令與DOM綁定在一起,再擴展指令的行為。

例如, ng-click 可以讓一個元素能夠監(jiān)聽 click 事件,并在接收到事件的時候執(zhí)行AngularJS表 達式。

我們可以自己創(chuàng)造新的指令。使用angular的directive( )這個模塊是用來定義指令的。

2.知識剖析

一個完整的自定義指令所包含的內(nèi)容

angular.module(...);

.directive('My-directive', function(injectables) {

restrict: 'A',

priority: 0,

template: '',

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 是一個可選的參數(shù)。它告訴AngularJS這個指令在DOM中可以何種形式被聲明。默 認(rèn)AngularJS認(rèn)為 restrict 的值是 A ,即以屬性的形式來進行聲明。

restrict 值可以是以下幾種:

E 作為元素名使用

A 作為屬性使用

C 作為類名使用

M 作為注釋使用

template (字符串或函數(shù))

template 參數(shù)是可選的,必須被設(shè)置為以下兩種形式之一:

? 一段HTML文本;

? 一個可以接受兩個參數(shù)的函數(shù),參數(shù)為 tElement 和 tAttrs ,并返回一個代表模板的字符 串。

templateUrl,引入外部的一個html文件

指令中的SCOPE

directive 默認(rèn)能共享父 scope 中定義的屬性,例如在模版中直接使用父 scope 中的對象和屬性。

通常使用這種直接共享的方式可以實現(xiàn)一些簡單的 directive 功能。但是當(dāng)要創(chuàng)建一個可以重復(fù)使用的

directive的時候, 就不能依賴于父scope了,因為在不同的地方使用directive對應(yīng)的父scope不一樣。

所以需要一個隔離的scope。

2.2 scope屬性的3種取值

①、false(默認(rèn)值):直接使用父scope。

②、true:繼承父scope

③、對象{ }:創(chuàng)建一個新的“隔離”scope,但仍可與父scope通信。隔離的scope,通常用于創(chuàng)建可復(fù)用的指令,也就是它不用管父scope中的model。然而雖然說是“隔離”,但通常我們還是需要讓這個子scope跟父scope中的變量進行綁定。綁定的策略有3種:@、=、&。

@ 這是一個單項綁定的前綴標(biāo)識符

使用方法:在元素中使用屬性,好比這樣 my-name="{{name}}",注意,屬性的名字要用-將兩個單詞連接,因為是數(shù)據(jù)的單項綁定所以要通過使用{{}}來綁定數(shù)據(jù)。

= 這是一個雙向數(shù)據(jù)綁定前綴標(biāo)識符

使用方法:在元素中使用屬性,好比這樣 my-age="age",注意,數(shù)據(jù)的雙向綁定要通過=前綴標(biāo)識符實現(xiàn),所以不可以使用{{}}。

& 這是一個綁定函數(shù)方法的前綴標(biāo)識符

使用方法:在元素中使用屬性,好比這樣 my-change="changeAge()",注意,屬性的名字要用-將多個個單詞連接。

指令中的 CONTROLLER , COMPILE , LINK函數(shù)

AngularJs 的生命周期;分為兩個階段:

第一個階段是編譯階段: 在編譯階段,AngularJS會遍歷整個HTML文檔并根據(jù)JavaScript中的指令定義來處理頁面上聲明的指令。

每一個指令的模板中都可能含 有另外一個指令,另外一個指令也可能會有自己的模板。當(dāng)AngularJS調(diào)用HTML文檔根部的指令時,

會遍歷其中所有的模板,模板中也可能包 含帶有模板的指令.一旦對指令和其中的子模板進行遍歷或編譯,

編譯后的模板會返回一個叫做模板函數(shù)的函數(shù)。我們有機會在指令的模板函 數(shù)被返回前,對編譯后的DOM樹進行修改。

第二個階段是鏈接階段:鏈接函數(shù)來將模板與作用域鏈接起來;負(fù)責(zé)設(shè)置事件監(jiān)聽器,監(jiān)視數(shù)據(jù)變化和實時的操作DOM.鏈接函數(shù)是可選的。

如果定義了編譯函數(shù),它會返回鏈接函數(shù),因此當(dāng)兩個函數(shù)都定義了時,編譯函數(shù)會重載鏈接函數(shù)

指令的控制器和link函數(shù)可以進行互換。控制器主要是用來提供可在指令間復(fù)用的行為,但鏈接函數(shù)只能在當(dāng)前內(nèi)部指令中定義行為,

且無法在指令間復(fù)用.link函數(shù)可以將指令互相隔離開來,而controller則定義可復(fù)用的行為。

3.常見問題

scope屬性的3種取值對指令有什么影響?

4.解決方案

每當(dāng)一個指令被創(chuàng)建的時候,都會有這樣一個選擇,是繼承自己的父作用域(一般是外部的Controller提供的作用域或者根作用域($rootScope)),還是創(chuàng)建一個新的自己的作用域,當(dāng)然AngularJS為我們指令的scope參數(shù)提供了三種選擇,分別是:false,true,{};默認(rèn)情況下是false。

當(dāng)scope參數(shù)被設(shè)置為false時有什么情況發(fā)生在這種情況下,在指令模板中可以直接使用父作用域中的變量,函數(shù)

因為我們將scope的屬性設(shè)置為false所以,我們創(chuàng)建的指令繼承了父作用域的一切屬性和方法,這也使得在指令的模板中我們可以使用這些屬性和方法。

注意:此時我們在輸入框里改變名字,會發(fā)現(xiàn)上面的兩個名字都發(fā)生了變化

4.2 scope = true。

當(dāng)把scope屬性設(shè)置為true時,這表明我們創(chuàng)建的指令要創(chuàng)建一個新的作用域,這個作用域繼承自我們的父作用域。

修改上面的JS代碼,將指令中的:scope:false修改為scope:true "

然后我們再試著在我們的input輸入框中寫一些字符串,會發(fā)現(xiàn),指令中的那個name發(fā)生了變化,但是指令外的那個name卻沒有發(fā)生變化,這說明了一個問題。

當(dāng)我們將scope設(shè)置為true的時候,我們就新創(chuàng)建了一個作用域,只不過這個作用域是繼承了我們的父作用域;我覺得可以這樣理解,我們新創(chuàng)建的作用域是一個新的作用域,只不過在初始化的時候,用了父作用域的屬性和方法去填充我們這個新的作用域。它和父作用域不是同一個作用域。

當(dāng)我們將scope設(shè)置為false的時候,我們創(chuàng)建的指令和父作用域(其實是同一個作用域)共享同一個model模型,所以在指令中修改模型數(shù)據(jù),它會反映到父作用域的模型中。

4.3 scope = {}

當(dāng)我們將scope的屬性設(shè)置為{}時,我們可以做更多的事情。

AngularJS最強的大的地方之一就是它可以構(gòu)建組件,無論放在哪里都是可以使用的;這所以可以做到這些,不得不歸功于指令的這個屬性;當(dāng)我們將scope設(shè)置為{}時,意味著我們創(chuàng)建的一個新的與父作用域隔離的新的作用域,這使我們在不知道外部環(huán)境的情況下,就可以正常工作,不依賴外部環(huán)境。

我們使用了隔離的作用域,不代表我們不可以使用父作用域的屬性和方法。

我們可以通過向scope的{}中傳入特殊的前綴標(biāo)識符(即prefix),來進行數(shù)據(jù)的綁定。

在創(chuàng)建了隔離的作用域,我們可以通過@,&,=引用應(yīng)用指令的元素的屬性

下面我們來看看如何使用這些前綴標(biāo)識符:

1.@:單向綁定,外部scope能夠影響內(nèi)部scope,但反過來不成立;

這是一個單項綁定的前綴標(biāo)識符。使用方法:在元素中使用屬性,好比這樣注意,屬性的名字要用-將兩個單詞連接,因為是數(shù)據(jù)的單項綁定所以要通過使用{{}}來綁定數(shù)據(jù)。

2、=:雙向綁定,外部scope和內(nèi)部scope的model能夠相互改變;

這是一個雙向數(shù)據(jù)綁定前綴標(biāo)識符。使用方法:在元素中使用屬性,好比這樣注意,數(shù)據(jù)的雙向綁定要通過=前綴標(biāo)識符實現(xiàn),所以不可以使用{{}}。

3、&:把內(nèi)部scope的函數(shù)的返回值和外部scope的任何屬性綁定起來。

這是一個綁定函數(shù)方法的前綴標(biāo)識符。使用方法:在元素中使用屬性,好比這樣

注意,屬性的名字要用-將多個個單詞連接。

5.編碼實戰(zhàn)

6.擴展思考

我們的指令是如何利用這些前綴標(biāo)識符來尋找我們想要的屬性或者函數(shù)的?

@ 當(dāng)指令編譯到模板的name時,就會到scope中尋找是否含有name的鍵值對,如果存在,就像上面那樣,看到@就知道這是一個單向的數(shù)據(jù)綁定,然后尋找原來的那個使用指令的元素上(或者是指令元素本身)含有這個值的屬性即my-name={{name}},然后在父作用域查找{{name}}的值,得到之后傳遞給模板中的name。

=和&與@差不多,只不過=進行的是雙向的數(shù)據(jù)綁定,不論模板還是父作用域上的屬性的值發(fā)生改變都會使另一個值發(fā)生改變,而&是綁定函數(shù)而已。

7.參考文獻

參考一:AngularJS 自定義指令

參考二:一招制敵 - 玩轉(zhuǎn) AngularJS 指令的 Scope (作用域)

8.更多討論

Q1:王姣妍:

講一下指令中的controller和link的區(qū)別?

A1:王棟:

指令的控制器和link函數(shù)可以進行互換??刂破髦饕怯脕硖峁┛稍谥噶铋g復(fù)用的行為,但鏈接函數(shù)只能在當(dāng)前內(nèi)部指令中定義行為,且無法在指令間復(fù)用.link函數(shù)可以將指令互相隔離開來,而controller則定義可復(fù)用的行為。

實際使用的一些建議:

如果我們希望將當(dāng)前指令的API暴露給其他指令使用,可以使用controller參數(shù),否則可以使用link來構(gòu)造當(dāng)前指令元素的功能性。如果我們使用了scope.$watch()或者想要與DOM元素做實時的交互,使用鏈接會是更好的選擇。

Q2:王姣妍:

操作dom的內(nèi)容放在link中,那么在link中是怎么操作dom的?

A2:王棟:


Q3:王姣妍:

scope:false和scope{x:‘=’}的區(qū)別

A3:王棟

scope:false是作用域內(nèi)所有的屬性都雙向綁定,而scope:{x:‘=’}只對設(shè)置等號的屬性進行雙向綁定!



如何理解angularjs的directive的scope屬性

PPT

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容