Vue中的MVVM(2)--view -> model的綁定

再次看了上次寫(xiě)的博客關(guān)于Vue的MVVM,發(fā)現(xiàn)雖然介紹了MVVM的原理,但是感覺(jué)還不夠詳細(xì)癞己,現(xiàn)在就再次根據(jù)這篇博客寫(xiě)詳細(xì)一點(diǎn)案狠,來(lái)看看new Vue的時(shí)候Vue究竟做了些什么事总滩。
我想纯蛾,以需求作為出發(fā)點(diǎn)來(lái)理解原理會(huì)比較容易舶沛,所以這篇博客會(huì)以提出需求 -> 解決需求的方式來(lái)寫(xiě)冠王。

項(xiàng)目地址,歡迎start

Vue中的MVVM原理介紹

可以先閱讀我的這篇博客了解一下關(guān)于Vue的MVVM舌镶,另外需要記住這一幅圖(很重要)柱彻,這張圖就是本篇博客的概括:

image.png

回顧

繼上一篇文章Vue中的MVVM--model -> view的綁定,我們完成了對(duì)頁(yè)面的初始化渲染餐胀,達(dá)成了如下要求:

image.png

image.png

但還未完成view -> model的綁定否灾,所以不能通過(guò)修改數(shù)據(jù)來(lái)觸發(fā)視圖的更新卖擅,今天就來(lái)完成剩余部分

提出需求

繼上圖:


image.png

我們需要做到的是:當(dāng)修改輸入框的數(shù)據(jù)時(shí),上面的文字也隨之進(jìn)行刷新墨技。

分析

先來(lái)看看還未完成的部分:

image.png

其中包含觀察者Observer断楷,監(jiān)聽(tīng)器Watcher,然后還有一個(gè)Dep崭别,過(guò)程是:

  1. Compiler中監(jiān)聽(tīng)數(shù)據(jù)的變化并綁定監(jiān)聽(tīng)器冬筒;
  2. 在觀察者Observer中實(shí)現(xiàn)對(duì)所有數(shù)據(jù)的gettersetter恐锣;
  3. 監(jiān)聽(tīng)器Watcher把更新事件添加進(jìn)Dep的事件隊(duì)列中;
  4. 觀察者Observer發(fā)現(xiàn)數(shù)據(jù)產(chǎn)生變化的時(shí)候通知Dep舞痰;
  5. Dep把事件隊(duì)列中的更新事件全部執(zhí)行一遍土榴;

總結(jié)下來(lái)就是實(shí)現(xiàn)兩個(gè)事情:

  1. 添加數(shù)據(jù)依賴;
  2. 觸發(fā)數(shù)據(jù)變更事件响牛;
    接下來(lái)就先創(chuàng)建Watcher玷禽,ObserverDep三個(gè)類呀打;
    image.png

    image.png

    image.png

先來(lái)看看Dep是什么

根據(jù)上面的的步驟描述论衍,很容易感覺(jué)到Dep像是一個(gè)容器,存儲(chǔ)著對(duì)視圖的更新事件聚磺,是的,這是一個(gè)發(fā)布訂閱模式的實(shí)現(xiàn)炬丸,該模式包含事件隊(duì)列subs瘫寝,添加事件方法addSub,執(zhí)行事件隊(duì)列函數(shù)notify稠炬,移除事件隊(duì)列里的事件removeSub

image.png

看完發(fā)布訂閱模式后焕阿,繼續(xù)我們的流程。

添加依賴

  • 在Compiler中監(jiān)聽(tīng)數(shù)據(jù)的變化并綁定監(jiān)聽(tīng)器
    在上一篇對(duì)model -> view的綁定中我們有一個(gè)針對(duì)數(shù)據(jù)和指令統(tǒng)一進(jìn)行綁定的方法bind首启,為了不和后面的v-bind指令沖突暮屡,現(xiàn)在改為了bindData;

    image.png

    在這個(gè)函數(shù)承載的功能有獲取tag文本和執(zhí)行視圖的更新,所以我們可以在這個(gè)函數(shù)中添加對(duì)數(shù)據(jù)的監(jiān)聽(tīng)器Watcher毅桃,因?yàn)楹竺嫘枰迅乱晥D的事件添加進(jìn)Dep中褒纲,所以Watcher中需要的參數(shù)要有一個(gè)更新事件也就是更新器updater中的視圖更新函數(shù),此外將當(dāng)前vm實(shí)例和得到的data鍵值也傳進(jìn)去備用;
    compile中添加數(shù)據(jù)監(jiān)聽(tīng)器

    更新器

    watcher

    接著

  • 在觀察者Observer中實(shí)現(xiàn)對(duì)所有數(shù)據(jù)的getter和setter
    注意這一步需要考慮到數(shù)據(jù)中含有嵌套的對(duì)象钥飞,需要進(jìn)行遞歸操作才能全部添加gettersetter莺掠,使用的是Object.definedPropertyObserver接受的參數(shù)是data對(duì)象:

    image.png

    然后在MVVM類中代入data并執(zhí)行observer:
    image.png

    接著對(duì)所有data中的屬性綁定gettersetter读宙,這一步需要進(jìn)行遞歸操作:
    image.png

    最后回到Compiler中彻秆,實(shí)現(xiàn)視圖對(duì)數(shù)據(jù)的修改:
    比如在輸入框中修改數(shù)據(jù)直接反應(yīng)到data
    image.png

    image.png

    來(lái)看看成果:
    image.png

    這個(gè)時(shí)候在視圖上對(duì)數(shù)據(jù)進(jìn)行的修改就可以反映到data上,并觸發(fā)該數(shù)據(jù)的setter函數(shù)结闸;

  • 監(jiān)聽(tīng)器Watcher把更新事件添加進(jìn)Dep的事件隊(duì)列中唇兑;
    這一步需要考慮一個(gè)問(wèn)題:在什么時(shí)候怎么樣把更新事件添加到Dep中去?
    回顧上面所寫(xiě)的,data中的每一個(gè)屬性都有一個(gè)對(duì)應(yīng)的Watcher桦锄,可以在Watcher中獲取得到對(duì)應(yīng)的data中的屬性扎附。那么在這個(gè)獲取的過(guò)程中,又會(huì)觸發(fā)該屬性的getter结耀,就可以考慮在該屬性的getter中添加帕棉,分解成一下步驟就是:
    ① 把這個(gè)Watcher通過(guò)構(gòu)造函數(shù)本身的屬性target保留在Dep中针肥,然后去data中取值;

    image.png

    ② 取值的時(shí)候觸發(fā)Observer中該屬性的getter香伴,在Observer中new一個(gè)Dep實(shí)例出來(lái)慰枕,判斷如果Dep類的target非空(也就是該屬性已被有監(jiān)聽(tīng)器),則觸發(fā)依賴添加事件depend;
    image.png

    ③ 這時(shí)候的Dep.target就是被監(jiān)聽(tīng)屬性的Watcher即纲,在Dep類中添加一個(gè)方法depend具帮,用來(lái)把該屬性的Watcher添加進(jìn)事件隊(duì)列subs中,但是這一步要當(dāng)前的Watcher低斋,需要在Watcher類中進(jìn)行觸發(fā)蜂厅,所以在Watcher中創(chuàng)建一個(gè)函數(shù)addDep,把Dep的實(shí)例作為參數(shù)放進(jìn)去膊畴,然后在addDep中進(jìn)行更新事件的添加:
    image.png

    image.png

    然后置空Dep.target掘猿,用于下一個(gè)數(shù)據(jù)的依賴添加
    image.png

    現(xiàn)在我們來(lái)看看subs中有些什么
    image.png

    可見(jiàn)msg被引用了兩次就被監(jiān)聽(tīng)了兩次,這時(shí)候只要當(dāng)msg這個(gè)數(shù)據(jù)發(fā)生變化并觸發(fā)setter時(shí)唇跨,將subs中所有的watcher實(shí)例里的更新回調(diào)update拉出來(lái)執(zhí)行即可

  • 更新視圖

  1. 更新視圖的時(shí)候稠通,我們先要獲取當(dāng)前的數(shù)據(jù)新值,然后作為參數(shù)放進(jìn)回調(diào)函數(shù)中买猖,并且還要對(duì)新的數(shù)據(jù)進(jìn)行上面的依賴添加步驟改橘,那么Watcher還需要一個(gè)update函數(shù)用來(lái)統(tǒng)一做這個(gè)事:
    image.png
  2. Observersetter中觸發(fā)Depnotify方法,進(jìn)行視圖的更新:
    image.png
  3. 到了這步其實(shí)就已經(jīng)達(dá)成效果了:


    image.png
  • 修復(fù)bug
    雖然MVVM雙向綁定的功能已經(jīng)達(dá)成玉控,但是還是有不少bug的飞主,其中最嚴(yán)重的有兩個(gè)
  1. 當(dāng)我們多次更新數(shù)據(jù)的時(shí)候,會(huì)發(fā)現(xiàn)添加進(jìn)subswatcher發(fā)生了遞增的現(xiàn)象高诺,所以當(dāng)快速更新數(shù)據(jù)時(shí)就會(huì)導(dǎo)致執(zhí)行函數(shù)過(guò)多而頁(yè)面崩潰碌识;

    image.png

    造成這個(gè)現(xiàn)象的原因是在進(jìn)行第一次的更新時(shí),watcher將同一個(gè)數(shù)據(jù)的新值也進(jìn)行了依賴添加虱而,也就是let newVal = this.get()這一段丸冕;
    image.png

    既然知道了原因,那么解決起來(lái)也很簡(jiǎn)單薛窥,給每一個(gè)被監(jiān)聽(tīng)的對(duì)象都添加一個(gè)id即可胖烛。
    因?yàn)樘砑觭ub的操作是在Watcher中進(jìn)行的,所以在Watcher中創(chuàng)建一個(gè)對(duì)象depIds
    image.png

    然后給每一個(gè)Dep都添加一個(gè)不同的id
    image.png

    最后在Watcher中判斷depIds是否已經(jīng)有這個(gè)id的Dep實(shí)例存在诅迷,如果沒(méi)有則添加進(jìn)去并執(zhí)行addSub佩番,否則不執(zhí)行:
    image.png

    效果,無(wú)論怎么修改罢杉,都只會(huì)有固定數(shù)量的Watcher存在:
    image.png

  2. 當(dāng)修改數(shù)據(jù)為對(duì)象的時(shí)候趟畏,這個(gè)對(duì)象沒(méi)有進(jìn)行監(jiān)聽(tīng),這個(gè)也好解決滩租,只要在setter中進(jìn)行判斷即可赋秀,若為對(duì)象則針對(duì)該對(duì)象重新進(jìn)行監(jiān)聽(tīng)

    image.png

總結(jié)

到這里為止利朵,我們就完成了view -< model的綁定,并且知道在new Vue的時(shí)候大致做了一些什么事了猎莲,剩下的就是逐步完善绍弟,例如對(duì)更多指令的支持,對(duì)methods以及computedwatch的支持著洼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末樟遣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子身笤,更是在濱河造成了極大的恐慌豹悬,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件液荸,死亡現(xiàn)場(chǎng)離奇詭異瞻佛,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)娇钱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門伤柄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人忍弛,你說(shuō)我怎么就攤上這事】汲” “怎么了细疚?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)川梅。 經(jīng)常有香客問(wèn)我疯兼,道長(zhǎng),這世上最難降的妖魔是什么贫途? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任吧彪,我火速辦了婚禮,結(jié)果婚禮上丢早,老公的妹妹穿的比我還像新娘姨裸。我一直安慰自己,他們只是感情好怨酝,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布傀缩。 她就那樣靜靜地躺著,像睡著了一般农猬。 火紅的嫁衣襯著肌膚如雪赡艰。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,262評(píng)論 1 308
  • 那天斤葱,我揣著相機(jī)與錄音慷垮,去河邊找鬼揖闸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛料身,可吹牛的內(nèi)容都是我干的汤纸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼惯驼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蹲嚣!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起祟牲,我...
    開(kāi)封第一講書(shū)人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤隙畜,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后说贝,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體议惰,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年乡恕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了言询。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡傲宜,死狀恐怖运杭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情函卒,我是刑警寧澤辆憔,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站报嵌,受9級(jí)特大地震影響虱咧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜锚国,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一腕巡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧血筑,春花似錦绘沉、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至园欣,卻和暖如春帖世,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工日矫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赂弓,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓哪轿,卻偏偏與公主長(zhǎng)得像盈魁,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子窃诉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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