vue3響應(yīng)式原理視頻講解(vue3實(shí)現(xiàn)原理)
今天給各位分享vue3響應(yīng)式原理視頻講解的知識(shí),其中也會(huì)對(duì)vue3實(shí)現(xiàn)原理進(jìn)行解釋?zhuān)绻芘銮山鉀Q你現(xiàn)在面臨的問(wèn)題,別忘了關(guān)注本站,現(xiàn)在開(kāi)始吧!
本文目錄一覽:
- 1、【Vue3】響應(yīng)式原理
- 2、vue3響應(yīng)式數(shù)據(jù)原理
- 3、【手把手教你搓Vue響應(yīng)式原理】(一)初識(shí)Vue響應(yīng)式
- 4、聊一聊 Vue3 中響應(yīng)式原理
- 5、【手把手教你搓Vue響應(yīng)式原理】(五) Watcher 與 Dep
【Vue3】響應(yīng)式原理
答:數(shù)據(jù)是可以進(jìn)行觀測(cè)的,也就是說(shuō)在讀取和設(shè)置的時(shí)候可以劫持它來(lái)做其他操作;
注意:數(shù)據(jù)響應(yīng)式和視圖更新是沒(méi)有關(guān)系的?。?!響應(yīng)式只是一種機(jī)制,一種數(shù)據(jù)變化的偵測(cè)機(jī)制,實(shí)現(xiàn)這種機(jī)制的方法也不是唯一的,就例如vue2和vue3實(shí)現(xiàn)響應(yīng)式的方法是不同的
vue3響應(yīng)式數(shù)據(jù)原理
Effect 原理解析 與 實(shí)現(xiàn)
引言:
vue、react 框架的核心都是數(shù)據(jù)驅(qū)動(dòng)視圖也就是model = view,實(shí)現(xiàn)的核心也就是 數(shù)據(jù)響應(yīng)。
主要就三步:
一、effect:副作用函數(shù)
1.類(lèi)似于vue2.0中watch 的升級(jí)版,如果函數(shù)中用到的響應(yīng)式的數(shù)據(jù)發(fā)生了變化,則會(huì)執(zhí)行該函數(shù)
二、proxy 與reflect
Object.defineProperty API 的一些缺點(diǎn):
vue3源碼的調(diào)試方法:
三、響應(yīng)式api reactive的實(shí)現(xiàn)
三、Effect的依賴收集與響應(yīng)觸發(fā) (分-總-分-問(wèn)題)
【手把手教你搓Vue響應(yīng)式原理】(一)初識(shí)Vue響應(yīng)式
在講這個(gè)之前,首先要明白一點(diǎn),這個(gè)所謂的響應(yīng)式,其實(shí)本身就是對(duì) MVVM 的理解。
MVVM 其實(shí)就是所謂的 Modal View ViewModal 。
簡(jiǎn)單理解,就是你的 data 中的數(shù)據(jù),和 template 模板中的界面,本身就是兩個(gè)東西。
但是, Vue 給你做了一層中間的 ViewModal ,讓視圖上的改變能反映到 data 中, data 中的改變能反映到視圖上。
在這個(gè)反映過(guò)程中,ViewModal就是視圖和數(shù)據(jù)的一個(gè)橋梁。
同樣是讓 a + 1 。
在 Vue 中,這個(gè)橋梁是你看不見(jiàn)的,因?yàn)? Vue 都幫你完成了視圖和數(shù)據(jù)的變化傳遞。
而 React 就是侵入式的,因?yàn)橐@式地聲明 setState ,通過(guò)它,來(lái)設(shè)置變量的同時(shí),設(shè)置視圖的改變。
所以,所謂的侵入式,其實(shí)就是對(duì)于橋梁的侵入。
所以, Vue 的神奇之處就在于,不需要我們手動(dòng)地顯示調(diào)用 setState ,也就是這個(gè)橋梁, Vue 已經(jīng)幫我們橋接上了。
要讓 data 改變的同時(shí),視圖也發(fā)生改變,所以,問(wèn)題的所在,就是我們需要監(jiān)聽(tīng),什么時(shí)候,這個(gè)變量發(fā)生了變量。
然而, ES5 中,就有那么一個(gè)特性,可以做到對(duì)于數(shù)據(jù)的劫持(監(jiān)聽(tīng))。
它就是 Object.defineProperty 。
Object.defineProperty( obj, prop, descriptor ) 方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性,并返回此對(duì)象,與此同時(shí),它可以對(duì) 對(duì)象的一些額外底層的屬性進(jìn)行設(shè)置 。例如可以設(shè)置 writable , enumerable , configurable 等屬性。
后面的額外屬性設(shè)置,才是我們使用它的重點(diǎn)。
但是,我們使用的不是上面的幾個(gè)屬性,最主要的還是它的 get set ,可以對(duì)屬性值的獲取和設(shè)置操作進(jìn)行攔截。
get主要是可以對(duì)值的獲取進(jìn)行攔截,,它必須要傳入一個(gè) return ,并且, 該函數(shù)的返回值會(huì)被用作屬性的值 。我們可以來(lái)看一個(gè)例子:
由于設(shè)置了 get ,所以,輸出 a.name 的時(shí)候直接會(huì)被攔截,走 get() 中的 return 所以,此時(shí), a.name 的值應(yīng)該是 你已經(jīng)被攔截了!。
set主要是可以對(duì)值的設(shè)置進(jìn)行攔截,該方法會(huì)接受一個(gè)參數(shù),那就是 被賦予的新值 。我們可以來(lái)看一個(gè)例子:
由于設(shè)置了 set ,所以,設(shè)置值的時(shí)候會(huì)被攔截,走 set() 中的方法。
所以, Vue 能自動(dòng)獲取data中的改變,反映到視圖的原因,就是有對(duì)于變量的獲取和設(shè)置的劫持,當(dāng)變量發(fā)生改變的同時(shí), Vue 能在第一時(shí)間知道,并且對(duì)視圖做出相應(yīng)的改變操作。
而這把鑰匙就是 Object.defineProperty 。
【尚硅谷】Vue源碼解析之?dāng)?shù)據(jù)響應(yīng)式原理
Object.defineProperty() - MDN
聊一聊 Vue3 中響應(yīng)式原理
Vue.js 3.0 "One Piece" 正式發(fā)布已經(jīng)有一段時(shí)間了,真可謂是千呼萬(wàn)喚始出來(lái)??!
相比于 Vue2.x , Vue3.0 在新的版本中提供了更好的性能、更小的捆綁包體積、更好的 TypeScript 集成、用于處理大規(guī)模用例的新 API 。
在發(fā)布之前,尤大大就已經(jīng)聲明了響應(yīng)式方面將采用 Proxy 對(duì)于之前的 Object.defineProperty 進(jìn)行改寫(xiě)。其主要目的就是彌補(bǔ) Object.defineProperty 自身的一些缺陷,例如無(wú)法檢測(cè)到對(duì)象屬性的新增或者刪除,不能監(jiān)聽(tīng)數(shù)組的變化等。
而 Vue3 采用了新的 Proxy 實(shí)現(xiàn)數(shù)據(jù)讀取和設(shè)置攔截,不僅彌補(bǔ)了之前 Vue2 中 Object.defineProperty 的缺陷,同時(shí)也帶來(lái)了性能上的提升。
今天,我們就來(lái)盤(pán)一盤(pán)它,看看 Vue3 中響應(yīng)式是如何實(shí)現(xiàn)的。
The Proxy object enables you to create a proxy for another object, which can intercept and redefine fundamental operations for that object. MDN
Proxy - 代理,顧名思義,就是在要訪問(wèn)的對(duì)象之前增加一個(gè)中間層,這樣就不直接訪問(wèn)對(duì)象,而是通過(guò)中間層做一個(gè)中轉(zhuǎn),通過(guò)操作代理對(duì)象,來(lái)實(shí)現(xiàn)修改目標(biāo)對(duì)象。
關(guān)于 Proxy 的更多的知識(shí),可以參考我之前的一篇文章 —— 初探 Vue3.0 中的一大亮點(diǎn)——Proxy ! ,這里我就不在贅述。
Vue3 中響應(yīng)式核心方法就是 reactive 和 effect , 其中 reactive 方法是負(fù)責(zé)將數(shù)據(jù)變成響應(yīng)式, effect 方法的作用是根據(jù)數(shù)據(jù)變化去更新視圖或調(diào)用函數(shù),與 react 中的 useEffect 有點(diǎn)類(lèi)似~
其大概用法如下:
默認(rèn)會(huì)執(zhí)行一次,打印 Hello , 之后更改了 data.name 的值后,會(huì)在觸發(fā)執(zhí)行一次,打印 World 。
我們先看看 reactive 方法的實(shí)現(xiàn)~
reactive.js
首先應(yīng)該明確,我們應(yīng)該導(dǎo)出一個(gè) reactive 方法,該方法有一個(gè)參數(shù) target ,目的就是將 target 變成響應(yīng)式對(duì)象,因此返回值就是一個(gè)響應(yīng)式對(duì)象。
reactive 方法基本結(jié)構(gòu)就是如此,給定一個(gè)對(duì)象,返回一個(gè)響應(yīng)式對(duì)象。
其中 isObject 方法用于判斷是否是對(duì)象,不是對(duì)象不需要代理,直接返回即可。
reactive 方法的重點(diǎn)是 Proxy 的第二個(gè)參數(shù) handler ,它承載監(jiān)控對(duì)象變化,依賴收集,視圖更新等各項(xiàng)重大責(zé)任,我們重點(diǎn)來(lái)研究這個(gè)對(duì)象。
handler.js
在 Vue3 中 Proxy 的 handler 主要設(shè)置了 get , set , deleteProperty , has , ownKeys 這些屬性,即攔截了對(duì)象的讀取,設(shè)置,刪除, in 以及 Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法。
這里我們偷個(gè)懶,暫時(shí)就考慮 set 和 get 操作。
handler.get()
get 獲取屬性比較簡(jiǎn)單,我們先來(lái)看看這個(gè),這里我們用一個(gè)方法創(chuàng)建 getHanlder 。
這里推薦使用了 Reflect.get 而并非 target[key] 。
可以發(fā)現(xiàn), Vue3 是在取值的時(shí)候才去遞歸遍歷屬性的,而非 Vue2 中一開(kāi)始就遞歸 data 給每個(gè)屬性添加 Watcher ,這也是 Vue3 性能提升之一。
handler.set()
同理 set 操作,我們也是用一個(gè)方法創(chuàng)建 setHandler 。
Reflect.set 會(huì)返回一個(gè) Boolean 值,用于判斷屬性是否設(shè)置成功。
完事后將 handler 導(dǎo)出,然后在 reactive 中引入即可。
測(cè)試幾組對(duì)象貌似沒(méi)啥問(wèn)題,其實(shí)是有一個(gè)坑,這個(gè)坑也跟數(shù)組有關(guān)。
如上例子,如果我們選擇代理數(shù)組,在 setHandler 中打印其 key 和 value 的話會(huì)得到 3 4 , length 4 這兩組值:
如果不作處理,那么會(huì)導(dǎo)致如果更新視圖的話,則會(huì)觸發(fā)兩次,這肯定是不允許的,因此,我們需要將區(qū)分新增和修改這兩種操作。
Vue3 中是通過(guò)判斷 target 是否存在該屬性來(lái)區(qū)分是新增還是修改操作,需要借助一個(gè)工具方法 —— hasOwnProperty 。
這里我們將上述的 createSetter 方法修改如下:
如此一來(lái),我們調(diào) push 方法的時(shí)候,就只會(huì)觸發(fā)一次更新了,非常巧妙的避免了無(wú)意義的更新操作。
effect.js
光上述構(gòu)造響應(yīng)式對(duì)象并不能完成響應(yīng)式的操作,我們還需要一個(gè)非常重要的方法 effect ,它會(huì)在初始化執(zhí)行的時(shí)候存儲(chǔ)跟其有關(guān)的數(shù)據(jù)依賴,當(dāng)依賴數(shù)據(jù)發(fā)生變化的時(shí)候,則會(huì)再次觸發(fā) effect 傳遞的函數(shù)。
其基本雛形如下,入?yún)⑹且粋€(gè)函數(shù),還有個(gè)可選參數(shù) options 方便后面計(jì)算屬性等使用,暫時(shí)不考慮:
createReactiveEffect 就是為了將 fn 變成響應(yīng)式函數(shù),監(jiān)控?cái)?shù)據(jù)變化,執(zhí)行 fn 函數(shù),因此該函數(shù)是一個(gè)高階函數(shù)。
createReactiveEffect 將原來(lái)的 fn 轉(zhuǎn)變成一個(gè) reactvieEffect , 并將當(dāng)前的 effect 掛到全局的 activeEffect 上,目的是為了一會(huì)與當(dāng)前所依賴的屬性做好對(duì)應(yīng)關(guān)系。
我們必須要將依賴屬性構(gòu)造成 { prop : [effect,effect] } 這種結(jié)構(gòu),才能保證依賴屬性變化的時(shí)候,依次去觸發(fā)與之相關(guān)的 effect ,因此,需要在 get 屬性的時(shí)候,做屬性的依賴收集,將屬性與 effect 關(guān)聯(lián)起來(lái)。
依賴收集 —— track
在獲取對(duì)象的屬性時(shí),會(huì)觸發(fā) getHandler ,再次做屬性的依賴收集,即 Vue2 中的發(fā)布訂閱。
在 setHandler 中獲取屬性的時(shí)候,做一次 track(target, key) 操作。
整個(gè) track 的數(shù)據(jù)結(jié)構(gòu)大概是這樣
目的就是將 target , key , effect 之間做好對(duì)應(yīng)的關(guān)系映射。
打印 targetMap 的結(jié)構(gòu)如下:
**觸發(fā)更新 —— trigger **
上述已經(jīng)完成了依賴收集,剩下就是監(jiān)控?cái)?shù)據(jù)變化,觸發(fā)更新操作,即在 setHandler 中添加 trigger 觸發(fā)操作。
這樣一來(lái),獲取數(shù)據(jù)的時(shí)候通過(guò) track 進(jìn)行依賴收集,更新數(shù)據(jù)的時(shí)候再通過(guò) trigger 進(jìn)行更新,就完成了整個(gè)數(shù)據(jù)的響應(yīng)式操作。
再回頭看看我們先前提到的例子:
控制臺(tái)會(huì)依次打印 Hello ***** effect ***** 以及 World ***** effect ***** , 分別是首次渲染觸發(fā)跟更新數(shù)據(jù)重渲染觸發(fā),至此功能實(shí)現(xiàn)!
整體來(lái)說(shuō), Vue3 相比于 Vue2 在很多方面都做了調(diào)整,數(shù)據(jù)的響應(yīng)式只是冰山一角,但是可以看出尤大團(tuán)隊(duì)非常巧妙的利用了 Proxy 的特點(diǎn)以及 es6 的數(shù)據(jù)結(jié)構(gòu)和方法。另外, Composition API 的模式跟 React 在某些程度上有異曲同工之妙,這種設(shè)計(jì)模式讓我們?cè)趯?shí)際開(kāi)發(fā)使用中更加的方法快捷,值得我們?nèi)W(xué)習(xí),加油!
最后附上倉(cāng)庫(kù)地址 github ,歡迎各位大佬批評(píng)斧正~
【手把手教你搓Vue響應(yīng)式原理】(五) Watcher 與 Dep
【手把手教你搓Vue響應(yīng)式原理】(一)初識(shí)Vue響應(yīng)式
【手把手教你搓Vue響應(yīng)式原理】(二)深度監(jiān)測(cè)對(duì)象全部屬性
【手把手教你搓Vue響應(yīng)式原理】(三)observe 以及 ob
【手把手教你搓Vue響應(yīng)式原理】(四) 數(shù)組的響應(yīng)式處理
之前已經(jīng)將數(shù)據(jù)劫持已經(jīng)全部完成了。
那么,接下來(lái),主要的要點(diǎn)就是在于兩點(diǎn),依賴收集和觸發(fā)依賴更新。
它的意義主要在于控制哪些地方使用了這個(gè)變量,然后,按照最小的開(kāi)銷(xiāo)來(lái)更新視圖 。
首先,要先明白,依賴是什么,比方說(shuō)在我們的模板中有 {{a}} ,那么,這個(gè)地方就有對(duì)于變量 a 的依賴。
在模板編譯的時(shí)候,就會(huì)觸發(fā) a 變量的 getter 。
然后,當(dāng)我們執(zhí)行 a++; 的時(shí)候,那么,我們就要觸發(fā)依賴的更新,當(dāng)初模板中 {{a}} 的地方,就要更新,是吧!
所以,我們都是 在 getter 中收集依賴,在 setter 中觸發(fā)依賴更新 。
這一節(jié)的內(nèi)容,主要就是用來(lái)專(zhuān)門(mén)講清楚這兩件事情。
依賴收集和觸發(fā)依賴更新主要由兩個(gè)類(lèi)來(lái)完成, Dep 和 Watcher 。
Dep 和 Watcher 在設(shè)計(jì)模式中,就是 發(fā)布-訂閱者 的模式。
而依賴,你可以理解為所謂的訂閱者。
Dep 說(shuō)白了就是發(fā)布者,它的工作就是依賴管理,要知道哪些地方用到了這個(gè)變量,可能用到這個(gè)變量的地方有很多,所以,它會(huì)有多個(gè)訂閱者。
然后,每個(gè)變量都應(yīng)該有屬于自己的 Dep ,因?yàn)槊總€(gè)變量所在的依賴位置是不一樣的,所以他們的訂閱者也不一樣。
然后在變量更新之后,就去通知所有的訂閱者(Watcher),我的變量更新了,你們?cè)撚|發(fā)視圖更新了。
Watcher 說(shuō)白了就是訂閱者,它接受 Dep 發(fā)過(guò)來(lái)的更新通知之后,就去執(zhí)行視圖更新了。
它其實(shí)就是所謂的 watch 監(jiān)聽(tīng)器,變量改變之后,執(zhí)行一個(gè)回調(diào)函數(shù)。
我們先按照?qǐng)D例來(lái)創(chuàng)建我們的 Dep 類(lèi)
根據(jù)我們的需求:
Dep 我們?cè)谇懊嬉舱f(shuō)了,每個(gè)屬性都應(yīng)該有它自己的 Dep ,用來(lái)管理依賴。
所以,首先,如果我們?cè)? Observer 中創(chuàng)建 Dep,那不就可以了。畢竟 Observer 會(huì)遍歷到每一個(gè)對(duì)象。
所以,很明顯,我們可以在 defineReactive 的 get 中收集依賴
因?yàn)橛辛? if(Dep.target) 的判斷,所以, 只有綁定 Watcher 的變量觸發(fā) getter 時(shí),才會(huì)添加依賴 。
這個(gè) Dep.target 其實(shí)就是 Watcher 的實(shí)例
所以,很明顯,我們可以在 defineReactive 的 set 中收調(diào)用 notify() 方法告知 Watcher 實(shí)例,數(shù)據(jù)更新了。
至此, Dep 的所有職責(zé),我們已經(jīng)幫它完成了。
其實(shí)照道理應(yīng)該有一個(gè)刪除依賴,我們這里就不再擴(kuò)展了。
首先, Watcher 實(shí)例應(yīng)該大家會(huì)相對(duì)而言更加好理解點(diǎn),因?yàn)?,我們有一個(gè) watch 偵聽(tīng)器,大家一定都很熟悉,這兩個(gè)其實(shí)一樣。
我們先按照?qǐng)D例來(lái)創(chuàng)建我們的 Watcher 類(lèi)
根據(jù)我們的需求:
這個(gè) parsePath 需要單獨(dú)拎出來(lái)說(shuō)一下,比方說(shuō)我們現(xiàn)在有這么一個(gè)對(duì)象
我們要監(jiān)聽(tīng)到 a.b.c.d ,所以,我們需要下面的這種格式
所以,這個(gè) get 很明顯就有點(diǎn)難度了。 我們需要通過(guò)循環(huán) 拿到 a.b 然后 .c 然后 .d。
我們將這個(gè)方法命名為 parsePath 。
入?yún)⒔邮芪覀兊? b.c.d ,我們可以看到 第一句執(zhí)行之后 segments=['b','c','d'] ,然后進(jìn)行第二層,這是返回了一個(gè)方法,按照循環(huán),那就是 obj=obj.b = obj=obj.c = obj=obj.d ,所以,就是返回一個(gè)對(duì)象的 obj.b.c.d,相當(dāng)于是遍歷字符串中的屬性樹(shù)。
在執(zhí)行 a.b.c.d=55; 的同時(shí),我們的控制臺(tái)就會(huì)輸出 ok 55 10 。
【尚硅谷】Vue源碼解析之?dāng)?shù)據(jù)響應(yīng)式原理
關(guān)于vue3響應(yīng)式原理視頻講解和vue3實(shí)現(xiàn)原理的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
掃描二維碼推送至手機(jī)訪問(wèn)。
版權(quán)聲明:本文由飛速云SEO網(wǎng)絡(luò)優(yōu)化推廣發(fā)布,如需轉(zhuǎn)載請(qǐng)注明出處。