基于angular中的重要指令詳解($eval,$parse和$compile)
在angular的服務(wù)中,有一些服務(wù)你不得不去了解,因?yàn)樗梢哉f(shuō)是ng的核心,而今天,我要介紹的就是ng的兩個(gè)核心服務(wù),$parse和$compile。其實(shí)這兩個(gè)服務(wù)講的人已經(jīng)很多了,但是100個(gè)讀者就有100個(gè)哈姆雷特,我在這里講講自己對(duì)于他們兩個(gè)服務(wù)的理解。
大家可能會(huì)疑問(wèn),$eval呢,其實(shí)他并不是一個(gè)服務(wù),他是scope里面的一個(gè)方法,并不能算服務(wù),而且它也基于parse的,所以只能算是$parse的另一種寫(xiě)法而已,我們看一下ng源碼中$eval的定義是怎樣的就知道了
$eval: function(expr, locals) {
return $parse(expr)(this, locals);
},
相信看完源碼大家就明白了吧,好了,現(xiàn)在就開(kāi)始兩種核心服務(wù)的講解了,如果感覺(jué)我說(shuō)的不對(duì)的話,歡迎在評(píng)論區(qū)或者私聊指出,免得禍害其他讀者。
再講這兩個(gè)服務(wù)的時(shí)候,我要先講一個(gè)在本貼的概念:上下文
我相信,很多人都聽(tīng)過(guò)這個(gè)“上下文”,但是可能有點(diǎn)模糊,在我這里給大家解釋解釋看看大家接不接受這個(gè)說(shuō)法。
還記得angular的數(shù)據(jù)綁定嗎?比如:我現(xiàn)在有個(gè)有個(gè)叫TestCtrl的控制器,他的內(nèi)容如下:
.controller('TestCtrl', function($scope) {
$scope.test = "Boo!!!"
})
而在html中我們的代碼是這樣的
<body ng-controller="TestCtrl">
{{test}}
</body>
那么,大家不用想都知道結(jié)果了,頁(yè)面上肯定會(huì)顯示 Boo!!!的字樣。
但是如果我刪掉ng-controller的指令呢?也就是我沒(méi)有在html申明控制器,你直接綁定{{test}}會(huì)如何呢?
結(jié)果只有一個(gè),那就是頁(yè)面啥都沒(méi)有(ps:因?yàn)槟闵昝髁薾g-app)。講到這里大家明白了嗎?
控制器就相當(dāng)于一個(gè)上下文的容器,真正的上下文其實(shí)是$scope,當(dāng)頁(yè)面綁定test,如果申明了控制器,當(dāng)前上下文就是控制器里面的$scope,ng會(huì)去找一下你這個(gè)控制器的上下文$scope有沒(méi)有test,如果有,他當(dāng)然就顯示出來(lái)了,但是你不申明控制器的時(shí)候呢?他的上下文容器就是ng-app了,那么他真正的上下文就是$rootScope,這個(gè)時(shí)候他就會(huì)尋找$rootScope有沒(méi)有test。
好了,上下文的概念已經(jīng)講完了,其實(shí)挺容易理解的,基本上和this非常相似
那么言歸正傳,我們開(kāi)始講$parse,首先我們要看的是ng的API文檔
var getter = $parse('user.name');
var setter = getter.assign;
var context = {user:{name:'angular'}};
var locals = {user:{name:'local'}};
expect(getter(context)).toEqual('angular');
setter(context, 'newValue');
expect(context.user.name).toEqual('newValue');
expect(getter(context, locals)).toEqual('local');
大家看到的是ng文檔里面對(duì)于$parse服務(wù)性價(jià)比最高的幾行代碼,
getter和setter就是大家所熟知的get方法和set方法了,context和locals僅僅是json對(duì)象而已,目的就是模擬上下文關(guān)系
大家看到的下面四個(gè)語(yǔ)句最終都能通過(guò)測(cè)試,現(xiàn)在我們一個(gè)個(gè)來(lái)分析,分析之前我要解釋一遍什么叫$parse
$parse服務(wù)其實(shí)就是一種解析表達(dá)式的功能,就像ng-model=“test”,你在html中寫(xiě)這個(gè)東西誰(shuí)知道你ng-model=“test”中,其實(shí)你想綁定的是當(dāng)前控制器(上下文容器)中scope(上下文)中的test里面的值,ng就是通過(guò)$parse服務(wù)去幫助你解析這個(gè)表達(dá)式的,所以在調(diào)用$parse服務(wù)的時(shí)候你需要傳遞上下文對(duì)象,讓ng知道你是要去哪里的scope(上下文)去找你這個(gè)test。
所以我們看到第一行測(cè)試代碼是這樣的:
getter(context)).toEqual('angular') //實(shí)際上就是 $parse('user.name')(context)
在這個(gè)context就是上下文,他能返回“angular“這個(gè)字符串的原理就是經(jīng)過(guò)這三步的:
1.獲取當(dāng)前的表達(dá)式user.name
2.獲取當(dāng)前的上下文對(duì)象{user:{name:'angular'}}
3.在上下問(wèn)對(duì)象中尋找表達(dá)式,最終獲得“angular“這個(gè)字符創(chuàng)
所以這句測(cè)試代碼是成功的。
我們看第二個(gè)方法setter方法
setter(context, 'newValue');//實(shí)際上就是 $parse('user.name').assign(context, 'newValue')
expect(context.user.name).toEqual('newValue');//測(cè)試數(shù)據(jù)上下文的值是否被改變
這里的setter方法其實(shí)是改變值得方法
1.獲取當(dāng)前的表達(dá)式user.name
2.獲取當(dāng)前的上下文對(duì)象{user:{name:'angular'}}
3.改變表達(dá)式中的值,將上下文對(duì)象編程{user:{name:'newValue'}}
于是上下文對(duì)象發(fā)生了改變,重新用getter方法去獲取表達(dá)式的時(shí)候,上下文已經(jīng)從{user:{name:'angular'}} --> {user:{name:'newValue'}},最后獲取的表達(dá)式的值自然就是“newValue”了,所以測(cè)試代碼也是通過(guò)的。
expect(getter(context, locals)).toEqual('local');//實(shí)際上就是$parse('user.name')(context, locals)
這里要表現(xiàn)的其實(shí)是上下文的替換功能。
在getter的方法中我們不僅可以選擇第一個(gè)上下文,但是如果我們傳遞了第二個(gè)參數(shù),那么第一個(gè)上下文就會(huì)被第二個(gè)上下文覆蓋,注意是覆蓋.
1.獲取當(dāng)前的表達(dá)式user.name
2.獲取當(dāng)前的上下文對(duì)象{user:{name:'angular'}}
3.覆蓋當(dāng)前的上下文{user:{name:'local'}}
4.獲取解析之后表達(dá)式的值
重新回到$eval這個(gè)地方,我們看待$eval源碼中可以看出$eval只有g(shù)et功能,而沒(méi)有set功能,但是有些時(shí)候我們可以選擇傳遞第二個(gè)上下文,來(lái)達(dá)到修改值得效果。
在這里$parse服務(wù)就已將說(shuō)完了,接下來(lái)就是$compile
--------------------------------------------------
如果你了解了$parse的概念之后,我想$compile也差不多理解了,其實(shí)和$parse很像。但是他是解析一段html代碼的,他的功能就是將死模板變成活模板,也是指令的核心服務(wù)。
比如你有一段html代碼 <h1>{{test}}</h1>,如果你將這段代碼直接放在html代碼里面,它所呈現(xiàn)的內(nèi)容是怎樣的我不說(shuō)大家也應(yīng)該懂。這就是死模板了,而所謂的活模板,就是這里面的數(shù)據(jù)全部經(jīng)過(guò)了數(shù)據(jù)的綁定 {{test}}會(huì)自動(dòng)找到當(dāng)前的上下文,來(lái)綁定數(shù)據(jù)。最后顯示出來(lái)的 就是活模板,也就是經(jīng)過(guò)數(shù)據(jù)綁定的模板。
$compile('死模板')(上下文對(duì)象),這樣就將死模板編程了活模板,你就可以對(duì)這段活的html代碼做操作了,例如增加到當(dāng)前節(jié)點(diǎn),等等。
但是在指令中,她會(huì)返回兩個(gè)函數(shù)pre-link和post-link
第一個(gè)執(zhí)行的是pre-link,它對(duì)于同一個(gè)指令的遍歷順序是從父節(jié)點(diǎn)到子節(jié)點(diǎn)的遍歷,在這個(gè)階段,dom節(jié)點(diǎn)還沒(méi)有穩(wěn)定下來(lái),無(wú)法做一些綁定事件的操作,但是我們可以在這里進(jìn)行一些初始化數(shù)據(jù)的處理。
第二個(gè)執(zhí)行的是post-link,也就是我們常說(shuō)的link函數(shù),他是從子節(jié)點(diǎn)到父節(jié)點(diǎn)遍歷的,在這個(gè)階段,DOM節(jié)點(diǎn)已經(jīng)穩(wěn)定下來(lái)了,我們一般會(huì)在這里進(jìn)行很多的操作。
以上就是小編為大家?guī)?lái)的基于angular中的重要指令詳解($eval,$parse和$compile)全部?jī)?nèi)容了,希望大家多多支持腳本之家~
相關(guān)文章
Angular 開(kāi)發(fā)學(xué)習(xí)之Angular CLI的安裝使用
這篇文章主要介紹了Angular 開(kāi)發(fā)學(xué)習(xí)之Angular CLI的安裝使用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
詳解@angular/cli 改變默認(rèn)啟動(dòng)端口兩種方式
這篇文章主要介紹了詳解@angular/cli 改變默認(rèn)啟動(dòng)端口兩種方式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-11-11
詳解AngularJs ui-router 路由的簡(jiǎn)單介紹
本篇文章主要介紹了AngularJs ui-router 路由的簡(jiǎn)單介紹。簡(jiǎn)單明了的說(shuō)明了ngRoute和ui-router的區(qū)別和用法,有興趣的可以了解一下2017-04-04
Angular 多模塊項(xiàng)目構(gòu)建過(guò)程
這篇文章主要介紹了Angular 多模塊項(xiàng)目構(gòu)建過(guò)程,本文大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02
AngularJS基礎(chǔ) ng-paste 指令簡(jiǎn)單示例
本文主要介紹AngularJS ng-paste 指令,這里對(duì)ng-paste 指令的基礎(chǔ)資料做了整理,并附有代碼示例,有需要的朋友可以參考下2016-08-08
Angular實(shí)現(xiàn)表格自滾動(dòng)效果
這篇文章主要為大家介紹了如何通過(guò)Angular實(shí)現(xiàn)表格自動(dòng)滾動(dòng)的效果,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Angular有一定幫助,需要的可以參考一下2022-01-01
Angular實(shí)現(xiàn)模版驅(qū)動(dòng)表單的自定義校驗(yàn)功能(密碼確認(rèn)為例)
這篇文章主要介紹了Angular實(shí)現(xiàn)模版驅(qū)動(dòng)表單的自定義校驗(yàn)功能(密碼確認(rèn)為例),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-05-05
AngularJS入門教程之MVC架構(gòu)實(shí)例分析
這篇文章主要介紹了AngularJS的MVC架構(gòu),結(jié)合實(shí)例形式重點(diǎn)分析了ng-controller聲明并使用控制器的操作技巧與控制器作用域的相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-11-11

