徹底學(xué)會(huì)Angular.js中的transclusion
前言
AngularJS中指令的重要性是不言而喻的,指令讓我們可以創(chuàng)建自己的HTML標(biāo)記,它將自定義元素變成了一個(gè)一個(gè)的模塊,極大的體現(xiàn)了前端開發(fā)中的模塊化模式,并提高了代碼的易讀性和重用性。AngularJS中的指令也是學(xué)習(xí)AngularJS中的一個(gè)難點(diǎn)所在,其中的許多屬性,需要反復(fù)學(xué)習(xí),認(rèn)真體會(huì),方能領(lǐng)悟其中的精妙之處。
今天我們要講的就是其中一個(gè)重點(diǎn)和難點(diǎn) – transclusion。關(guān)于這個(gè)話題我之前也寫過很多文章來講述,但是當(dāng)時(shí)都是照搬博文中的例子,自己也沒有比較深刻的體會(huì),因此一直不得要領(lǐng)。今天我們的目標(biāo)就是“徹底弄懂transclusion”。
一、什么是transclusion
好吧,我知道你肯定會(huì)去查詞典,但是你會(huì)發(fā)現(xiàn),詞典上沒有transclusion這個(gè)詞的準(zhǔn)確釋義?。?!納尼?。?!這不坑爹的嗎!?。?!
還好,維基百科上有一個(gè)注釋,翻譯過來意思大概是這樣的:
transclusion在計(jì)算機(jī)科學(xué)中指的是講一個(gè)文檔或者一個(gè)文檔的某部分在另一個(gè)文檔中引用。
我去,這不坑爹的嗎!?。∈裁匆馑迹。。。?/p>
確實(shí),你猜對(duì)了,這個(gè)解釋對(duì)我們一點(diǎn)幫助都沒有!?。。。。?/p>
還好,我們終于在某道詞典找到了一個(gè)解釋:“嵌入”,這里指的是transclusion這個(gè)詞,而在后面我們即將看到的transclude這個(gè)詞壓根在詞典上就找不到。算了,淡定一點(diǎn),繼續(xù)往下看。其實(shí)這里翻譯為“嵌入”,如果從實(shí)際運(yùn)用中來看,還是比較貼切的。如果你不太理解什么是transclusion,我們下面用一個(gè)例子來說明一下。
ok,現(xiàn)在我們要?jiǎng)?chuàng)建一個(gè)指令了,我們把這個(gè)指令叫做<handsome-me>
。在此先略過這個(gè)指令的創(chuàng)建過程,如果你還不知道怎樣創(chuàng)建一個(gè)指令,請(qǐng)前參看前面幾篇文章。
好了,無論怎么說,這個(gè)指令已經(jīng)創(chuàng)建好了,于是我們可以有以下幾種用法:
第一種:
<handsome-me/>
就像是input一樣對(duì)吧,很簡單,我們叫它“自開自閉”(要是你在別的書上沒看過這個(gè)名稱,那就是我發(fā)明的,反正就這么叫)標(biāo)簽。
第二種:
<handsome-me></handsome-me>
就像是div一樣對(duì)吧,更簡單,我們叫它“自開別人閉”(同上同上)標(biāo)簽。
第三種:
<handsome-me> //中間有好多代碼 </handsome-me>
這個(gè)和第二種很像吧,但是又有點(diǎn)區(qū)別,我們叫它“自開別人閉,中間加一坨”(總是感覺好粗俗。。。never mind。。。)標(biāo)簽。
我們來對(duì)比以下三種標(biāo)簽,它們有什么區(qū)別。當(dāng)然區(qū)別很多。但是具體到我們今天的話題,與之相關(guān)的最大的區(qū)別就是前兩種中間沒有加一坨,第三種中間加了一坨。OK,因此我們現(xiàn)在來總結(jié)什么叫做transclusion:
如果你在定義指令的時(shí)候,想要它在具體使用時(shí)中間加一坨,那么你就要用transclusion。
這個(gè)定義實(shí)在是太經(jīng)典了,完全比什么官方文檔要清楚有沒有,完爆各種老外唧唧歪歪說半天還是不明白有沒有,完全符合中國國情有沒有!?。?/p>
好了,知道了定義以后,我們要開始來看看具體怎么使用transclusion了。如果你了解AngularJS指令的編寫,你一定知道return的那個(gè)對(duì)象的tranclude指令默認(rèn)是false,因此如果你想要開啟使用transclusion的話,就要將這個(gè)transclude屬性賦上一個(gè)別的值,當(dāng)然,這個(gè)值不能亂賦,它只有兩種選擇:
第一種選擇:
transclude: true
第二種選擇:
transclude: 'element'
我去,這個(gè)又是毛線啊!兩者之間有毛的區(qū)別?。?!文檔完全是看不懂的嘛?。?!
淡定一點(diǎn),現(xiàn)在我們來說區(qū)別。最常用的呢,是第一種,也就是賦值為true。還記得transclusion的中文意思嗎,“嵌入”對(duì)吧!因此我們現(xiàn)在就不說“一坨”,而把中間的這一坨叫做“嵌入部分”。ok,回到正題,當(dāng)transclude是true的時(shí)候,嵌入部分就是嵌入部分,比如說:
<handsome-me> {{name}} <handsome-me>
在transclude:true
的時(shí)候,它的嵌入部分是什么???對(duì)了,就是{{name}}
。再來一發(fā):
<handsome-me> <div> <span>{{name}}</span> </div> <handsome-me>
在transclude:true
的時(shí)候,它的嵌入部分是什么?。繉?duì)了,是
<div> <span>{{name}}</span> </div>
太簡單了是吧!so easy!媽媽再也不用擔(dān)心我的學(xué)習(xí)?。?!
現(xiàn)在再來講第二種情況,當(dāng)transclude的值是element的時(shí)候,又是怎樣一種情形。此時(shí),嵌入部分變成了原來的嵌入部分加上外邊的自定義標(biāo)簽,也就是整個(gè)元素。又聽不懂了?。?!fork fork fork!!!!!!淡定,我們?cè)賮砼e例子:
<handsome-me> {{name}} <handsome-me>
在transclude:'element'
的時(shí)候它的嵌入部分是什么???對(duì)了,是:
<handsome-me> {{name}} <handsome-me>
再來一發(fā):
<handsome-me> <div> <span>{{name}}</span> </div> <handsome-me>
在transclude:'element'
的時(shí)候它的嵌入部分是什么?。繉?duì)了,是:
<handsome-me> <div> <span>{{name}}</span> </div> <handsome-me>
都說的這么詳細(xì)了,不要再說你不會(huì)了哈?。。?/p>
二、ng-transclude的作用是什么
在編寫指令時(shí),我們都會(huì)有一個(gè)template或者templateUrl這樣的屬性是吧。在使用transclusion時(shí),我們要把嵌入部分放到模板中,因此我們有兩種選擇,其中一種選擇就是使用ng-transclude。
ng-transclude是干什么用的,我們還是先來看定義,再來看例子:
ng-tranclude決定了在什么地方放置嵌入部分。
太好理解了!于是我們來看例子:
假設(shè)指令是這樣的:
<handsome-me> {{name}} </handsome-me>
而模板是這樣的:
<div> <p>MaMa does not need to worry about my study anymore! </p> <div ng-transclude></div> </div>
于是,在transclude:true
的情況下,最終呈現(xiàn)在頁面中的HTML會(huì)是什么樣子。對(duì)了,是這樣:
<div> <p>MaMa does not need to worry about my study anymore! </p> {{name}} </div>
另一種情況,在transclude:'element'
的情況下,最終呈現(xiàn)在頁面中的HTML會(huì)是什么樣子。對(duì)了,是這樣:
<div> <p>MaMa does not need to worry about my study anymore! </p> <handsome-me> {{name}} </handsome-me> </div>
例子這么清楚,總能明白了吧?。?/p>
三、不使用ng-transclude的情形
OK,現(xiàn)在我們來想一個(gè)問題,如果我想把我的嵌入部分多次放入我的模板中怎么辦?你可能會(huì)說,那就多放幾個(gè)ng-transclude唄!這當(dāng)然是不行的,在AngularJS中你只在一個(gè)指令的模板中只能申明一個(gè)ng-tranclude。所以這種情況下我們就能使用模板了,因此我們要使用一個(gè)叫做tranclude()
的函數(shù)!!
納尼!這又是什么東西?。?!如果你仔細(xì)去研究一下AngularJS的文檔的話,你一定會(huì)發(fā)現(xiàn)一個(gè)叫做$tranclude的service,它就是我們現(xiàn)在要將講的東西。那么這個(gè)函數(shù)怎么用?如果你看過一些關(guān)于ng-repeat,ng-swift源碼的解析,你一定會(huì)記得其中的一個(gè)叫做linker的東西。這個(gè)東西上是什么曾經(jīng)困擾過我好長時(shí)間,但是后來我發(fā)現(xiàn)這個(gè)linker()
其實(shí)就是transclude()
。
我們?cè)趌ink,compile以及controller中都能找到這個(gè)transclude函數(shù)的身影。在link函數(shù)中,transclude是link函數(shù)的第五個(gè)參數(shù);在compile函數(shù)中,transclude是compile函數(shù)的第三個(gè)參數(shù)。在這個(gè)兩個(gè)函數(shù)中,由于我們沒有使用依賴注入,因此只要順序?qū)α司蛯?duì)了,隨便命名為什么都可以。而在controller函數(shù)中,由于使用的是依賴注入,因此transclude是$transclude,只要名字寫對(duì)了就對(duì)了。在link,compile和controller函數(shù)中,transclude的用法一模一樣,因此在這我們只舉一個(gè)link函數(shù)的例子:
1.最簡單的用法:
link(scope,elem,attrs,ctrl,transclude){ var content = transclude(); elem.append(content); }
在這里,我們通過transclude()
返回了嵌入部分的具體內(nèi)容,然后append到了元素的elem的尾巴上,當(dāng)然,你想要append多次也是可以的。
2.復(fù)雜一點(diǎn)的用法:
link(scope,elem,attrs,ctrl,transclude){ tranclude(scope,function(clone){ elem.append(clone); }) }
這里tranclude接受了兩個(gè)參數(shù),第一個(gè)是scope,代表作用域。第二個(gè)回調(diào)函數(shù)中帶有一個(gè)參數(shù)clone,其實(shí)它就是嵌入內(nèi)容,和transclude()
的返回值一模一樣。那么前面的第一個(gè)參數(shù)的scope有什么用呢?這就要說到transclude和作用域了!
4.transclude和scope
我們知道,在定義一個(gè)指令時(shí),如果不顯式聲明scope,那么指令的作用域就是父作用域。如果聲明scope:true
或者scope:{}
,那么指令會(huì)生成一個(gè)自己的作用域,只不過一個(gè)原型繼承,一個(gè)獨(dú)立而已。如果你使用transclusion,那么無論什么情緒,都會(huì)生成一個(gè)新的作用域,這個(gè)作用域直接原型繼承于父作用域,它的地位和指令生成的作用域是一樣的,二者屬于并列的關(guān)系。
于是我們現(xiàn)在就能了解tranclude(scope,function(clone){})
中的scope是什么意思了,默認(rèn)情況下,如果我們簡單使用translude()
,那么作用域默認(rèn)的是transclude生成的自作用域。但是如果我們使用tranclude(scope,function(clone){})
,那么作用域顯然就是directive的作用域了。要是我們想使用父作用域怎么辦,很簡單:
tranclude(scope.$parent,function(clone){})
要是想要一個(gè)新的作用域怎么辦,也很簡單:
tranclude(scope.$parent.$new(),function(clone){})
你要是文作用域是什么東西,作用域是怎么繼承的,那不是今天我們要講的話題。
說了這么多,這么直白,想必你已經(jīng)對(duì)AngularJS的transclusion徹底的清楚明白了吧。要是不明白,再看幾遍,總會(huì)明白的?。。?/p>
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)各位Android開發(fā)者們能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
AngularJS控制器controller正確的通信的方法
AngularJS中的controller是個(gè)函數(shù),用來向視圖的作用域($scope)添加額外的功能,我們用它來給作用域?qū)ο笤O(shè)置初始狀態(tài),并添加自定義行為2016-01-01angular2 ng build部署后base文件路徑問題詳細(xì)解答
本篇文章主要介紹了angular2 ng build部署后base文件路徑問題詳細(xì)解答,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07JavaScript框架Angular和React深度對(duì)比
這篇文章主要介紹了JS框架中Angular和React不同和差異,以及兩個(gè)框架的深度對(duì)比介紹。2017-11-11angularjs中ng-bind-html的用法總結(jié)
這篇文章主要介紹了angularjs中ng-bind-html的用法總結(jié),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05