vue 的響應(yīng)式原理

這次我們一起做一個(gè)最小的 vue

首先我們要明白幾個(gè)概念。數(shù)據(jù)驅(qū)動(dòng),響應(yīng)式原理,發(fā)布訂閱模式和觀察者模式。

數(shù)據(jù)驅(qū)動(dòng)

數(shù)據(jù)響應(yīng)式,雙向綁定,數(shù)據(jù)驅(qū)動(dòng)。

數(shù)據(jù)響應(yīng)式:數(shù)據(jù)模型是普通的 JS 對(duì)象,數(shù)據(jù)變,視圖變。

雙向綁定:數(shù)據(jù)變,視圖變。視圖變,數(shù)據(jù)變。如 v-moudle.

數(shù)據(jù)驅(qū)動(dòng):只管數(shù)據(jù)變,數(shù)據(jù)怎么渲染到視圖中,不需要理會(huì)。這也是為什么 MVVM 框架火熱。

響應(yīng)式核心原理

vue 2.x :按照官網(wǎng)的說(shuō)法是基于 object.defineProperty?(不兼容 IE8 )把 data 中的屬性遍歷,轉(zhuǎn)化為 getter setter

object.defineProperty?:? ?https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

具體代碼如下圖 2.1

圖 2.1

vue 3.x?:是基于 ES6 中的 Proxy ,因?yàn)樗槍?duì)象,而不是屬性,所以面對(duì)多個(gè)對(duì)象可以省去遍歷

Proxy?可學(xué)習(xí)阮一峰老師整理的內(nèi)容? ? ? ?https://es6.ruanyifeng.com/#docs/proxy

代碼如下圖 2.2

圖 2.2


發(fā)布訂閱模式

在一個(gè)“信息中心”里存在發(fā)布者和訂閱者兩種角色,當(dāng)有新的消息,發(fā)布著會(huì)進(jìn)行推送,訂閱者會(huì)進(jìn)行接收。如圖 2.3

圖 2.3

實(shí)現(xiàn) vue $on? $emit 見(jiàn)圖2.4

圖2.4

觀察者模式

沒(méi)有“信息中心”,目標(biāo)(發(fā)布者)需要知道觀察者(訂閱者)的存在。目標(biāo)中存儲(chǔ)觀察者名單 subs,還有兩個(gè)方法, addSub() 添加觀察者, notify() 當(dāng)事件發(fā)生調(diào)用觀察者的? ? ??update() 方法

代碼見(jiàn)下圖2.5

圖2.5

好,在梳理上述概念時(shí)候,想必大家對(duì) vue 最基本的構(gòu)成也就有了一個(gè)大概認(rèn)知。

首先一個(gè) vue 類(lèi)型對(duì)象,負(fù)責(zé)注入數(shù)據(jù),把數(shù)據(jù)轉(zhuǎn)換成? getter setter ,調(diào)用 observer??和? compiler?

observer 數(shù)據(jù)劫持監(jiān)聽(tīng)數(shù)據(jù)變化,通知 dep(發(fā)布者)。

compiler 解析指令,替換插值表達(dá)式。

dep 負(fù)責(zé)添加觀察者,并調(diào)用觀察者 update

watcher 更新視圖。

綜上可總結(jié)出 關(guān)系圖2.6

圖2.6

我們先創(chuàng)建一個(gè) 使用了 vue 功能的模板,如下圖 2.7

圖 2.7

我們來(lái)回想一下 vue 的基本構(gòu)造。

每個(gè) vue 實(shí)例下邊都包含了 options data el 三個(gè)屬性。

根據(jù) 圖2.6 ,以及上述總結(jié),我們可以得知 vue 實(shí)現(xiàn)了什么以下四步功能。

1. 通過(guò)屬性保存選項(xiàng)的數(shù)據(jù)

2. 把 data 中的成員轉(zhuǎn)換成 getter setter ,注入到 vue 實(shí)例中

3.?調(diào)用 observer 對(duì)象,監(jiān)聽(tīng)數(shù)據(jù)的變化

4. 調(diào)用 compiler 對(duì)象,解析指令和差值表達(dá)式

有了以上四步,邏輯就很清晰了。然后可以得到代碼 圖2.8

?圖2.8

除了紅框里的內(nèi)容,其他的代碼在上邊都解釋了,這里也就不做贅述。

接下來(lái)我們來(lái)解決紅框里的兩個(gè)類(lèi)。

首先是 Observer ,我們想一下它做了什么 ,數(shù)據(jù)劫持監(jiān)聽(tīng)數(shù)據(jù)變化,并通知?dep(發(fā)布者)。

所謂的監(jiān)聽(tīng)數(shù)據(jù)變化。也就是把 data 中的數(shù)據(jù)轉(zhuǎn)化為 gettersetter ,方便 this 調(diào)用。但是這里與 vue 類(lèi)中不同的是。 Observer 還和 Dep 關(guān)聯(lián)。

我們來(lái)想一下, Dep 做了什么,無(wú)非就是添加觀察者和發(fā)布。

添加的時(shí)機(jī)顯然就是生成 getter 的時(shí)候, 發(fā)布就是 set 的時(shí)候。由此得出代碼 圖2.9

?圖2.9

好,出了上述代碼,大家一定對(duì)紅框框里的 dep 比較感興趣。對(duì)吧,你憑什么就突然一個(gè) Dep.target ,然后就開(kāi)始添加觀察者,這顯然不講道理。

好,講道理之前我們先看兩個(gè)其他的類(lèi),一個(gè) Dep ,一個(gè) watcher

Dep 無(wú)非就是添加和發(fā)布,上邊說(shuō)了,不再贅述,直接上才藝,圖2.10

圖2.10

簡(jiǎn)單樸實(shí)不難懂。然后是 watcher ,它是來(lái)干嘛的,顯然是監(jiān)控?cái)?shù)據(jù)變化。數(shù)據(jù)變化了然后編譯到頁(yè)面上。不難得出 watcher 的構(gòu)成就是,屬性,以及更新 DOM 的函數(shù)。

想要更新 DOM ,就少不了 Vue 實(shí)例和變化的屬性名稱(chēng),為了方便處理不同節(jié)點(diǎn)以及減少數(shù)據(jù)重復(fù)傳遞,我們一般會(huì)在實(shí)例化 watcher 時(shí)傳入處理函數(shù)。由此得出 圖 2.11

圖 2.11

這里就解釋清楚為什么會(huì)有?Dep.target?&&?dep.addSub(Dep.target) 這樣的代碼了。

最后一部分,也就是剩下的 compiler 類(lèi)了,它主要就是用來(lái)編譯節(jié)點(diǎn),根節(jié)點(diǎn) el ,實(shí)例 vm 。這都是必須的沒(méi)什么好說(shuō)的,設(shè)下的功能就是為了編譯。

vue 中的節(jié)點(diǎn)中我們只需要處理兩種,文本節(jié)點(diǎn)和帶有 v- 指令的元素節(jié)點(diǎn),所以整體代碼結(jié)構(gòu)如下圖,2.12.

圖,2.12.

三個(gè)判斷函數(shù),如下圖2.13,

圖2.13,

主函數(shù),根據(jù)條件進(jìn)行一個(gè)函數(shù)分發(fā)和遞歸

圖2.14

文本節(jié)點(diǎn)的處理,通過(guò)正則匹配 {} 中的內(nèi)容,如果內(nèi)容存在,就用他的值,替換到 node.textcontent 中,同時(shí)創(chuàng)建一個(gè) watcher 對(duì)象對(duì)該數(shù)據(jù)的后續(xù)變化進(jìn)行監(jiān)聽(tīng)并處理。

圖2.15

編譯節(jié)點(diǎn),遍歷屬性節(jié)點(diǎn),找到是 v- 指令的,進(jìn)行編譯,這里通過(guò) update 函數(shù)進(jìn)行了一次分發(fā),因?yàn)槭褂?if 分發(fā)太麻煩了,所有制令都要占行數(shù),

圖2.16

這兩個(gè)函數(shù)也比較簡(jiǎn)單,就是根據(jù)情況進(jìn)行一個(gè)修飾,

圖2.17

把寫(xiě)好的類(lèi)引入到 index 里,好,大公告成。

學(xué)了就問(wèn)老板要漲薪,隔壁員工都饞哭了!!!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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