vue核心之雙向綁定

雙向綁定如何實(shí)現(xiàn):

????????1互拾、我們需要一個(gè)方法來(lái)識(shí)別視圖中哪個(gè)元素被設(shè)置了雙向綁定世蔗。

????????2、我們需要監(jiān)視視圖和數(shù)據(jù)的變化珊随。

????????3述寡、我們需要將所有變化傳播到綁定視圖或者數(shù)據(jù)柿隙。

幾種實(shí)現(xiàn)數(shù)據(jù)雙向綁定的做法:1、發(fā)布者-訂閱者模式(backbone.js)鲫凶、臟值檢查(angular.js)禀崖、數(shù)據(jù)劫持(vue.js)。

發(fā)布者-訂閱者模式

? ??????視圖驅(qū)動(dòng)數(shù)據(jù)變化螟炫,主要應(yīng)用于input波附、select、textarea等元素昼钻,通過(guò)監(jiān)聽dom的change掸屡、keypress、keyup等事件來(lái)觸發(fā)事件改變數(shù)據(jù)層數(shù)據(jù)然评。

? ??????數(shù)據(jù)驅(qū)動(dòng)視圖變化仅财,一個(gè)數(shù)組對(duì)象el存放支持雙綁的dom對(duì)象,一個(gè)儲(chǔ)存 綁定值的對(duì)象data碗淌,一個(gè)儲(chǔ)存 設(shè)置值函數(shù)的對(duì)象fun盏求,一個(gè)調(diào)用函數(shù)set(循環(huán)每個(gè)el,再循環(huán)每個(gè)el的屬性,如果某個(gè)指定的屬性存在,就調(diào)用對(duì)應(yīng)fun),一旦改變數(shù)據(jù)就調(diào)用set函數(shù)亿眠。

臟值檢查:

? ? ? ? 和上種方式類似碎罚,但在數(shù)據(jù)驅(qū)動(dòng)視圖變化,不是改完值手動(dòng)觸發(fā)set函數(shù)觸發(fā)視圖更新缕探,而是通過(guò)setInterval()定時(shí)輪詢檢測(cè)數(shù)據(jù)變化觸發(fā)set函數(shù)魂莫。

數(shù)據(jù)劫持:? ??

? ? ? ? vue.js是通過(guò)數(shù)據(jù)劫持(object.defineProperty()的set和get)結(jié)合發(fā)布者-訂閱者方式,在數(shù)據(jù)變動(dòng)時(shí)發(fā)布消息給訂閱者爹耗,觸發(fā)相應(yīng)回調(diào)監(jiān)聽耙考。

? ? ? ? 1、實(shí)現(xiàn)一個(gè)數(shù)據(jù)監(jiān)聽器Observer潭兽,能夠?qū)?shù)據(jù)對(duì)象的所有屬性進(jìn)行監(jiān)聽倦始,如有變動(dòng)可拿到最新值并通知訂閱者。

? ? ? ? 2山卦、實(shí)現(xiàn)一個(gè)指令解析器Compile鞋邑,對(duì)每個(gè)元素節(jié)點(diǎn)的指令進(jìn)行掃描和解析,根據(jù)指令模版替換數(shù)據(jù)账蓉,以及綁定相應(yīng)的更新函數(shù)枚碗。

? ? ? ? 3、實(shí)現(xiàn)一個(gè)watcher铸本,做為連接Observer和Compile的橋梁肮雨,能夠訂閱并收到每個(gè)屬性變動(dòng)的通知。執(zhí)行指令綁定的相應(yīng)回調(diào)函數(shù)箱玷,從而更新視圖怨规。

? ? ? ? 4陌宿、mvvm入口函數(shù),整合以上三者波丰。

流程圖

分析

實(shí)現(xiàn)mvvm主要包括兩個(gè)方面壳坪,數(shù)據(jù)變化更新視圖,視圖變化更新數(shù)據(jù)掰烟。關(guān)鍵在于前者數(shù)據(jù)變化更新視圖爽蝴,后者可以通過(guò)事件監(jiān)聽即可。所以我們著重看前者媚赖。我們可以通過(guò)Object.defineProperty()對(duì)屬性設(shè)置一個(gè)set函數(shù)來(lái)觀察數(shù)據(jù)變化做出反應(yīng)霜瘪,我們來(lái)具體實(shí)現(xiàn)一下。

實(shí)現(xiàn)

我們需要一個(gè)觀察者Observer惧磺,以 遍歷遞歸 方式 為每個(gè)對(duì)象屬性通過(guò)Object.defineProperty()添加觀察颖对,在 獲取對(duì)象屬性getter函數(shù)中 需要在訂閱者Watcher初始化時(shí)把他裝進(jìn)訂閱器Dep,在?對(duì)象屬性值更新setter函數(shù)中 需要 改變oldVal—newVal磨隘,并通知訂閱者觸發(fā)相應(yīng)函數(shù)缤底。

我們需要一個(gè)訂閱者Watcher,它需要有初始化功能( 結(jié)合Observer的getter函數(shù)初始化時(shí)把自己添加進(jìn)Dep )番捂,需要在數(shù)據(jù)屬性值變化時(shí)个唧,調(diào)用相關(guān)函數(shù)重新賦予訂閱者新值。

我們需要一個(gè)解析者Compile设预,遍歷+遞歸 去解析dom節(jié)點(diǎn)徙歼,若解析到綁定相關(guān)字符串,就將初始化的數(shù)據(jù)初始化到視圖中鳖枕,實(shí)例化一個(gè)訂閱者并綁定更新函數(shù)魄梯。

? ? ? ? 1、實(shí)現(xiàn)一個(gè)觀察者Observer宾符,用來(lái)劫持并觀察所有屬性酿秸,如果有變動(dòng),就通知訂閱者魏烫。

? ? ? ? 2辣苏、實(shí)現(xiàn)一個(gè)訂閱者Watcher,可以收到屬性的變化并執(zhí)行相應(yīng)的函數(shù)哄褒,從而更新視圖稀蟋。

? ? ? ? 3、實(shí)現(xiàn)一個(gè)解析者compile呐赡,可以掃描和解析每個(gè)節(jié)點(diǎn)的相關(guān)指令糊治,并根據(jù)初始化模版數(shù)據(jù)去初始化相應(yīng)的訂閱器。

維護(hù)訂閱器

訂閱器

維護(hù)一個(gè)訂閱器罚舱,負(fù)責(zé)實(shí)例化訂閱者井辜,當(dāng)初始化和更新時(shí),調(diào)用相關(guān)函數(shù)管闷。

Dep為一個(gè)構(gòu)造函數(shù)粥脚,有subs數(shù)組儲(chǔ)存訂閱者,addSub和notify兩個(gè)函數(shù)包个,addSub負(fù)責(zé)在初始化訂閱者初始化時(shí)(當(dāng)Compile解析dom檢測(cè)到相關(guān)字符串 進(jìn)行訂閱者初始化)添加到訂閱器中刷允,notify負(fù)責(zé)在觀察到數(shù)據(jù)更新時(shí)被觸發(fā) 去調(diào)用訂閱者的更新函數(shù)。

實(shí)現(xiàn)Observe

observ

Observer主要是對(duì) 對(duì)象屬性 通過(guò) defineProperty()進(jìn)行監(jiān)聽碧囊,getter時(shí)幫助訂閱者初始化時(shí)加入訂閱器树灶,setter時(shí)更新對(duì)象屬性及通知訂閱者調(diào)用函數(shù)更新訂閱者值。

一個(gè)構(gòu)造函數(shù)Observer糯而,一個(gè)觸發(fā)函數(shù)observe天通。

observe函數(shù)判斷參數(shù)是否是對(duì)象,是的話實(shí)例化一個(gè)Observe對(duì)象(對(duì)象屬性 遍歷遞歸 時(shí)判斷子屬性值 是否是對(duì)象)熄驼。

Observe接受一個(gè)對(duì)象像寒,有Walk、defineReactive兩個(gè)函數(shù)瓜贾,Walk負(fù)責(zé)遍歷對(duì)象每個(gè)屬性調(diào)用defineReactive诺祸。defineReactive負(fù)責(zé)遞歸每個(gè)對(duì)象屬性 設(shè)置監(jiān)聽器。

Q/A

每次defineReactive都會(huì)new Dep()再在getter中初始化push訂閱者祭芦,Dep中怎么會(huì)有所有訂閱者筷笨?

其實(shí)只有一個(gè)訂閱者,每次都會(huì)實(shí)例一個(gè)Dep龟劲,有多個(gè)Dep胃夏。

setter時(shí)循環(huán)訂閱器中每個(gè)訂閱者調(diào)用update函數(shù),update函數(shù)做了什么事情咸灿?

監(jiān)聽器更新數(shù)據(jù)時(shí)觸發(fā)的更新函數(shù)判斷 new/old數(shù)據(jù)是否相同构订,不相同就把舊Value賦予新值,并在全局執(zhí)行回調(diào)函數(shù)(傳入新舊值)

實(shí)現(xiàn)訂閱者

訂閱者

????????每個(gè)訂閱者實(shí)例有4個(gè)對(duì)象屬性避矢,cb(監(jiān)聽器更新數(shù)據(jù)時(shí)觸發(fā)的函數(shù))悼瘾,vm(組件對(duì)象),exp(綁定的屬性key)审胸,value(綁定的屬性值)亥宿。run和get兩個(gè)函數(shù),run為監(jiān)聽器更新數(shù)據(jù)時(shí)觸發(fā)的更新函數(shù)判斷 new/old數(shù)據(jù)是否相同砂沛,不相同就把舊Value賦予新值烫扼,并在全局執(zhí)行回調(diào)函數(shù)(傳入新舊值)。get為初始化時(shí)把自己添加進(jìn)訂閱器Dep()中碍庵。

實(shí)現(xiàn)Compile

解析器主要作用是 遍歷遞歸解析dom節(jié)點(diǎn)映企,解析到雙向綁定的指令悟狱,將初始化的數(shù)據(jù)初始化到視圖中,實(shí)例化訂閱器并綁定更新函數(shù)堰氓。

第一部分

????????Compile構(gòu)造函數(shù)有3個(gè)屬性挤渐,vm(全局環(huán)境)el(html最高節(jié)點(diǎn))双絮,fragment用來(lái)存放dom節(jié)點(diǎn)(我們數(shù)據(jù)更新dom時(shí)需要多次操作dom浴麻,通過(guò)createDocumentFragment創(chuàng)建一個(gè)虛擬父節(jié)點(diǎn)fragment,把dom移入fragment進(jìn)行操作囤攀,操作完了直接替換整個(gè)dom(一次性替換操作效率更高比一次次操作塊70%)软免。

init()調(diào)用了nodeToFragment、compileElement焚挠、compile三個(gè)函數(shù)膏萧。

nodeToFragment,把dom塞入fragment虛擬父節(jié)點(diǎn)宣蔚。

compileElement向抢,遍歷遞歸fragment中dom,判斷是元素節(jié)點(diǎn)的話執(zhí)行compile函數(shù)胚委,是文本節(jié)點(diǎn)且有'{{}}'的話執(zhí)行compileText函數(shù)挟鸠。如果節(jié)點(diǎn)有子節(jié)點(diǎn)繼續(xù)遞歸執(zhí)行compileElement。

compile亩冬,對(duì)dom節(jié)點(diǎn)的屬性節(jié)點(diǎn)進(jìn)行遍歷艘希,若有"v-"相關(guān)字段屬性name,若有":on"相關(guān)字段則綁定的是事件硅急,執(zhí)行compileEvent事件覆享,否則執(zhí)行compileMdole事件

第二部分

"{{}}"對(duì)應(yīng)的compileText函數(shù)营袜,負(fù)責(zé)初始化節(jié)點(diǎn)textContent數(shù)據(jù)撒顿,并新增一個(gè)訂閱者。

"v-on:"對(duì)應(yīng)的compileEvent函數(shù)荚板,負(fù)責(zé)取得事件名和事件值 通過(guò)addEventListener監(jiān)聽函數(shù)觸發(fā)執(zhí)行對(duì)應(yīng)事件凤壁。

"v-model"對(duì)應(yīng)compileModel函數(shù),負(fù)責(zé)初始化節(jié)點(diǎn)value數(shù)據(jù)跪另,并新增一個(gè)訂閱者拧抖,再通過(guò)對(duì)node.addEventListener('input', function(...))在input數(shù)據(jù)變化時(shí)實(shí)時(shí)改變對(duì)象數(shù)據(jù)

第三部分

mvvm入口

入口

我們把整個(gè)流程結(jié)合起來(lái)看一遍

? ? ? ? 入口構(gòu)造函數(shù),需要一個(gè)數(shù)據(jù)對(duì)象data免绿,需要一個(gè)函數(shù)對(duì)象methods(當(dāng)data中數(shù)據(jù)變化時(shí)調(diào)用)唧席。

????????有一個(gè)proxyKeys函數(shù),作用,在訪問(wèn)selfVue的屬性時(shí)代理為selfVue.data屬性(this.data.name = 'canfoo'我們可以用更簡(jiǎn)潔的方式 this.name = 'canfoo'?)淌哟,也是通過(guò)遍歷每個(gè)data屬性為每個(gè)屬性添加監(jiān)聽器object.defineProperty()迹卢,在get內(nèi)把對(duì)this.key的訪問(wèn)替換成this.data.key的屬性值來(lái)處理。

? ? ? ? 監(jiān)聽器observe對(duì)數(shù)據(jù)對(duì)象進(jìn)行監(jiān)聽绞绒。

????????實(shí)例化compile對(duì)象婶希,把節(jié)點(diǎn)傳入,在compile會(huì)對(duì)dom節(jié)點(diǎn)進(jìn)行遍歷遞歸蓬衡,處理3種情況。1彤枢、"{{}}",初始化節(jié)點(diǎn)texteContent數(shù)值狰晚,實(shí)例化一個(gè)訂閱者。2缴啡、"v-model",初始化節(jié)點(diǎn)value數(shù)值壁晒,實(shí)例化一個(gè)訂閱者,并監(jiān)聽input事件實(shí)時(shí)對(duì)數(shù)據(jù)更新业栅。3秒咐、"v-on:"把對(duì)應(yīng)事件名和methods中事件進(jìn)行綁定監(jiān)聽addEventListener。

????????實(shí)例化訂閱者Watcher碘裕,會(huì)在初始化時(shí)把自己添加進(jìn)訂閱器Dep()携取,在數(shù)據(jù)更新時(shí)會(huì)通過(guò)this.c.call()觸發(fā)傳進(jìn)來(lái)的函數(shù) 處理數(shù)據(jù)。

? ? ? ? 所有事情處理好后執(zhí)行mounted函數(shù)帮孔。

二次理解:

我們定義好基本數(shù)據(jù)

基本數(shù)據(jù)

會(huì)有一個(gè)入口

入口

????????入口及之后做的事情:1雷滋、取到定義好的數(shù)據(jù)。2文兢、把對(duì)this.xxx的訪問(wèn)代理到this.data.xxx(寫法更簡(jiǎn)潔)晤斩。3、我們需要一個(gè)訂閱器Dep姆坚,來(lái)收集訂閱者Watcher澳泵,在觀察器檢測(cè)到數(shù)據(jù)變化時(shí),調(diào)用訂閱者Watcher的相關(guān)處理函數(shù)兼呵。4兔辅、執(zhí)行觀察者(Observe)遍歷遞歸 data屬性,通過(guò)訪問(wèn)器屬性O(shè)bject.defineProperty() 給他們都綁定觀察器萍程。5幢妄、執(zhí)行編譯者(Compile)分析編譯Dom結(jié)構(gòu),檢測(cè)到 相應(yīng)字符串 實(shí)例化一個(gè)訂閱者(Watcher)茫负,實(shí)例化時(shí)它會(huì)主動(dòng)觸發(fā)觀察者的getter函數(shù)把自己push進(jìn)訂閱器Dep蕉鸳。

首次數(shù)據(jù)賦值在什么時(shí)候?

????????首次數(shù)據(jù)賦值在解析者Compile解析到相關(guān)字符串時(shí) 實(shí)例化訂閱者Watcher的同時(shí)進(jìn)行了賦值。

之后數(shù)據(jù)更新 執(zhí)行流程如何潮尝?

????????觀察者Observe會(huì)在數(shù)據(jù)更新時(shí)觀察到榕吼,會(huì)執(zhí)行setter函數(shù)調(diào)用dep中notify函數(shù),notify函數(shù)再調(diào)用訂閱者的Update函數(shù)去調(diào)用相關(guān)方法處理勉失。

訂閱器Dep存在的意義羹蚣?

????????不知道?乱凿?顽素??? 每個(gè)Observer.prototype.defineReactive都會(huì)new Dep徒蟆。相當(dāng)于每個(gè)Watcher訂閱者都有一個(gè)Dep()胁出。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市段审,隨后出現(xiàn)的幾起案子全蝶,更是在濱河造成了極大的恐慌,老刑警劉巖寺枉,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抑淫,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡姥闪,警方通過(guò)查閱死者的電腦和手機(jī)始苇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)甘畅,“玉大人埂蕊,你說(shuō)我怎么就攤上這事∈柰伲” “怎么了蓄氧?”我有些...
    開封第一講書人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)槐脏。 經(jīng)常有香客問(wèn)我喉童,道長(zhǎng),這世上最難降的妖魔是什么顿天? 我笑而不...
    開封第一講書人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任堂氯,我火速辦了婚禮,結(jié)果婚禮上牌废,老公的妹妹穿的比我還像新娘咽白。我一直安慰自己,他們只是感情好鸟缕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開白布晶框。 她就那樣靜靜地躺著排抬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪授段。 梳的紋絲不亂的頭發(fā)上蹲蒲,一...
    開封第一講書人閱讀 51,231評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音侵贵,去河邊找鬼届搁。 笑死,一個(gè)胖子當(dāng)著我的面吹牛窍育,可吹牛的內(nèi)容都是我干的卡睦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼漱抓,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼么翰!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起辽旋,我...
    開封第一講書人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎檐迟,沒想到半個(gè)月后补胚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡追迟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年溶其,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片敦间。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瓶逃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出廓块,到底是詐尸還是另有隱情厢绝,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布带猴,位于F島的核電站昔汉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拴清。R本人自食惡果不足惜靶病,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一群井、第九天 我趴在偏房一處隱蔽的房頂上張望湿刽。 院中可真熱鬧,春花似錦羹奉、人聲如沸沪停。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至掷酗,卻和暖如春调违,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背泻轰。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工技肩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人浮声。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓虚婿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親泳挥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子然痊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • vue理解淺談 一 理解vue的核心理念 使用vue會(huì)讓人感到身心愉悅,它同時(shí)具備angular和react的優(yōu)點(diǎn)...
    ambeer閱讀 24,126評(píng)論 2 18
  • 前言 在之前面試中,有被問(wèn)到這個(gè)問(wèn)題屉符,雖然了解過(guò)是劫持Object.defineProperty方法剧浸,但是其細(xì)節(jié)并...
    Aleph_Zheng閱讀 1,072評(píng)論 0 5
  • 我的github: vue雙向綁定原理 MVC模式 以往的MVC模式是單向綁定,即Model綁定到View矗钟,當(dāng)我們...
    KlausXu閱讀 44,899評(píng)論 7 91
  • 這兩天在讀余華的作品《活著》唆香,在拿到這本書,看到名字就想這一定是講某個(gè)時(shí)代悲情的故事吨艇。講的肯定是主人公如何艱難的一...
    嫻靜雅之閱讀 272評(píng)論 0 0
  • 今后一定還會(huì)有好事發(fā)生的 有些時(shí)候 這個(gè)世界會(huì)讓你很沮喪 不過(guò)有件事是肯定的 要么好好活著 要么趕緊死 人生在世 ...
    衛(wèi)校一七藥二閱讀 729評(píng)論 0 19