摘要:實(shí)際上就是這里要表現(xiàn)的其實(shí)是上下文的替換功能。這就是死模板了,而所謂的活模板,就是這里面的數(shù)據(jù)全部經(jīng)過(guò)了數(shù)據(jù)的綁定會(huì)自動(dòng)找到當(dāng)前的上下文,來(lái)綁定數(shù)據(jù)。最后顯示出來(lái)的就是活模板,也就是經(jīng)過(guò)數(shù)據(jù)綁定的模板。
這篇文章是我兩年前在博客園寫(xiě)的,現(xiàn)在移植過(guò)來(lái),不過(guò)Angular 1.x 在國(guó)內(nèi)用的人已經(jīng)不多了,希望能幫助到有需要的人
在 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 中我們的代碼是這樣的
{{test}}
那么,大家不用想都知道結(jié)果了,頁(yè)面上肯定會(huì)顯示 Boo!!! 的字樣。
但是如果我刪掉 ng-controller 的指令呢?也就是我沒(méi)有在 html 申明控制器,你直接綁定{{test}}會(huì)如何呢?
結(jié)果只有一個(gè),那就是頁(yè)面啥都沒(méi)有(ps:因?yàn)槟闵昝髁?ng-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ù)性?xún)r(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ò)這三步的:
獲取當(dāng)前的表達(dá)式 user.name
獲取當(dāng)前的上下文對(duì)象{user:{name:"angular"}}
在上下問(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í)是改變值得方法
獲取當(dāng)前的表達(dá)式 user.name
獲取當(dāng)前的上下文對(duì)象{user:{name:"angular"}}
改變表達(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è)上下文覆蓋,注意是覆蓋.
獲取當(dāng)前的表達(dá)式 user.name
獲取當(dāng)前的上下文對(duì)象{user:{name:"angular"}}
覆蓋當(dāng)前的上下文{user:{name:"local"}}
獲取解析之后表達(dá)式的值
重新回到 $eval 這個(gè)地方,我們看待 $eval 源碼中可以看出$eval 只有 get 功能,而沒(méi)有 set 功能,但是有些時(shí)候我們可以選擇傳遞第二個(gè)上下文,來(lái)達(dá)到修改值得效果。
在這里 $parse 服務(wù)就已將說(shuō)完了,接下來(lái)就是 $compile
如果你了解了 $parse 的概念之后,我想 $compile 也差不多理解了,其實(shí)和 $parse 很像。但是他是解析一段 html 代碼的,他的功能就是將死模板變成活模板,也是指令的核心服務(wù)。
比如你有一段 html 代碼 {{test}}
,如果你將這段代碼直接放在 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)行很多的操作。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/92912.html
摘要:我們提取變量的目的就是為了在函數(shù)中生成相應(yīng)的變量賦值的字符串便于在函數(shù)中使用,例如這樣的話,只需要在調(diào)用這個(gè)匿名函數(shù)的時(shí)候傳入對(duì)應(yīng)的即可獲得我們想要的結(jié)果了。 showImg(https://segmentfault.com/img/bVSspq?w=4000&h=2670); 題圖:Vincent Guth 注:本文所有代碼均可在本人的個(gè)人項(xiàng)目colon中找到,本文也同步到了知乎專(zhuān)欄...
摘要:組件還包含數(shù)據(jù)事件的輸入與輸出,生命周期鉤子和使用單向數(shù)據(jù)流以及從父組件上獲取數(shù)據(jù)的事件對(duì)象備份。 說(shuō)明:參照了Angular1.x+es2015的中文翻譯,并將個(gè)人覺(jué)得不合適、不正確的地方進(jìn)行了修改,歡迎批評(píng)指正。 架構(gòu),文件結(jié)構(gòu),組件,單向數(shù)據(jù)流以及最佳實(shí)踐 來(lái)自@toddmotto團(tuán)隊(duì)的實(shí)用編碼指南 Angular 的編碼風(fēng)格以及架構(gòu)已經(jīng)使用ES2015進(jìn)行重寫(xiě),這些在Angul...
摘要:他們即不是指令,也不應(yīng)該使用組件代替指令,除非你正在用控制器升級(jí)模板指令,組件還包含數(shù)據(jù)事件的輸入與輸出,生命周期鉤子和使用單向數(shù)據(jù)流以及從父組件上獲取數(shù)據(jù)的事件對(duì)象。 showImg(https://segmentfault.com/img/bVynsJ); 關(guān)鍵詞 架構(gòu), 文件結(jié)構(gòu), 組件, 單向數(shù)據(jù)流以及最佳實(shí)踐 來(lái)自 @toddmotto 團(tuán)隊(duì)的編碼指南 Angular 的編碼...
摘要:屬性為時(shí),指示優(yōu)先級(jí)小于當(dāng)前指令的指令都不執(zhí)行,僅執(zhí)行到本指令。 作者:心葉時(shí)間:2018-04-22 10:58 一:自定義指令常用模板 下面是大致的說(shuō)明,不是全面的,后面來(lái)具體說(shuō)明一些沒(méi)有提及的細(xì)節(jié)和重要的相關(guān)知識(shí): angular.module(yelloxingApp, []).directive(uiDirective, function() { return { ...
摘要:具體可以查看抽象語(yǔ)法樹(shù)。而則是帶緩存的編譯器,同時(shí)以及函數(shù)會(huì)被轉(zhuǎn)換成對(duì)象。會(huì)用正則等方式解析模板中的指令等數(shù)據(jù),形成語(yǔ)法樹(shù)。是將語(yǔ)法樹(shù)轉(zhuǎn)化成字符串的過(guò)程,得到結(jié)果是的字符串以及字符串。里面的節(jié)點(diǎn)與父節(jié)點(diǎn)的結(jié)構(gòu)類(lèi)似,層層往下形成一棵語(yǔ)法樹(shù)。 寫(xiě)在前面 因?yàn)閷?duì)Vue.js很感興趣,而且平時(shí)工作的技術(shù)棧也是Vue.js,這幾個(gè)月花了些時(shí)間研究學(xué)習(xí)了一下Vue.js源碼,并做了總結(jié)與輸出。 文...
閱讀 2446·2021-11-22 13:53
閱讀 1136·2021-09-22 16:06
閱讀 1381·2021-09-02 15:21
閱讀 1912·2019-08-30 15:55
閱讀 3128·2019-08-29 11:19
閱讀 1927·2019-08-26 13:23
閱讀 948·2019-08-23 18:23
閱讀 1763·2019-08-23 16:06