詳解VUE響應(yīng)式原理
1、響應(yīng)式原理基礎(chǔ)
響應(yīng)式基本原理是基于Object.defineProperty(obj, prop, descriptor),?descriptor里面可以定義get和set方法,可以在獲取屬性值事觸發(fā)get方法(可以收集依賴(lài)),設(shè)置屬性值時(shí)觸發(fā)set方法(更新依賴(lài))。
擴(kuò)展:上面是vue2.0的響應(yīng)式基本原理,vue3.0的基本原理是Proxy,可以監(jiān)聽(tīng)屬性的get和set方法,監(jiān)聽(tīng)屬性的添加和刪除等等,比Object.defineProperty能力更強(qiáng),但是不兼容IE11。
2、核心對(duì)象:Dep與Watcher
Dep: vue在data里申明的每一個(gè)屬性都會(huì)生成一個(gè)Dep的實(shí)例對(duì)象,Dep.subs存儲(chǔ)著當(dāng)該屬性變化時(shí)需要去更新的Watcher;
Watcher: 有3種情況會(huì)生成Watcher的實(shí)例對(duì)象,分別為:
1.定義在computed里的計(jì)算屬性;
2.在watch里寫(xiě)的監(jiān)聽(tīng)函數(shù);
3.組件的渲染W(wǎng)atcher;
3、收集依賴(lài)與更新依賴(lài)
3.1 收集依賴(lài)
將Watcher的實(shí)例對(duì)象w分發(fā)到它所依賴(lài)的屬性的Dep中,過(guò)程如下:
1.將Dep.target = 當(dāng)前的Watcer 的實(shí)例對(duì)象w;
2.w執(zhí)行定義的函數(shù)(即在computed/watch寫(xiě)的函數(shù));
3.執(zhí)行函數(shù)的過(guò)程如果使用data里定義的屬性,則會(huì)觸發(fā)屬性的get方法,get方法中Dep實(shí)例對(duì)象dep會(huì)將Dep.target中存儲(chǔ)的w放入到dep.subs數(shù)組中,完成依賴(lài)收集。
說(shuō)明:Dep.target為當(dāng)前Watcer的實(shí)例對(duì)象
3.2 更新依賴(lài)
?當(dāng)修改我們申明的某個(gè)屬性時(shí),會(huì)觸發(fā)屬性的set方法,set方法會(huì)將dep.subs數(shù)組中收集的Watcher實(shí)例對(duì)象進(jìn)行更新,即觸發(fā)我們定義在computed和watch里面的函數(shù)。
4、源碼調(diào)試
4.1 測(cè)試的頁(yè)面代碼
<template>
<div>
<div>a:<input v-model="a" /></div>
<div>c:{{ c }}</div>
<div>b:<input v-model="b" /></div>
</div>
</template>
<script>
export default {
data: () => {
return {
a: '',
b: ''
}
},
computed: {
c() {
return 'source from ' + this.a;
}
},
watch: {
b() {
console.log('b changed');
}
}
};
</script>
上面的代碼vue初始化后會(huì)生成如下幾個(gè)對(duì)象:
1、對(duì)象說(shuō)明
屬性a和b對(duì)應(yīng)的Dep實(shí)例對(duì)象(收集a、b改變需要更新的Watcher):depA、depB;
頁(yè)面渲染函數(shù)生成對(duì)應(yīng)的Watcher實(shí)例對(duì)象updateWatcher;
computed屬性c生成對(duì)應(yīng)的Watcher實(shí)例對(duì)象:watcherC;
watch監(jiān)聽(tīng)屬性b生成對(duì)應(yīng)的Watcher實(shí)例對(duì)象:watcherB;
2、Dep與Watcher的關(guān)系
a、b變化頁(yè)面需要重新渲染,所以updateWatcher存在于depA和depB的subs中;
計(jì)算屬性c依賴(lài)屬性a的變化更更新,所以watcherC存在于depA的subs中;
b的變化會(huì)觸發(fā)定義watch 里b的監(jiān)聽(tīng)函數(shù),所以watcherB存在于depB的subs中;
3、最終的關(guān)系結(jié)果
最終屬性a收集的依賴(lài) depA.subs = [?updateWatcher,? watcherC];
最終屬性b收集的依賴(lài) depB.subs = [?updateWatcher,? watcherB];
4.2? 源碼調(diào)試
找到源碼文件:node_modules\vue\dist\vue.runtime.esm.js;
主要涉及如下幾個(gè)函數(shù):
1、收集依賴(lài)的入口函數(shù):initState(頁(yè)面初始化時(shí)執(zhí)行);
初始化順序是先data-->computed-->watch:原因是computed依賴(lài)data, watch依賴(lài)data和watch,被依賴(lài)的需要先初始化。

2、初始化computed和watch時(shí),生成Watcher實(shí)例化對(duì)象
先執(zhí)行Watcher.get函數(shù),將Dep.target = 當(dāng)前Watcher實(shí)例化對(duì)象


觸發(fā)收集依賴(lài)

執(zhí)行計(jì)算屬性里面的函數(shù),如果訪問(wèn)到data中的某個(gè)屬性時(shí),會(huì)觸發(fā)data屬性的get方法,觸發(fā)依賴(lài)收集:

當(dāng)修改這個(gè)屬性時(shí)會(huì)觸發(fā)set方法,會(huì)觸發(fā)更新dep.subs里面watcher對(duì)象

最終觸發(fā)Watcher的更新函數(shù),將待更新的watcher放入隊(duì)列中:

總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
vue2.0結(jié)合Element-ui實(shí)戰(zhàn)案例
這篇文章主要介紹了vue2.0結(jié)合Element-ui實(shí)戰(zhàn)案例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03
vant-ui組件調(diào)用Dialog彈窗異步關(guān)閉操作
這篇文章主要介紹了vant-ui組件調(diào)用Dialog彈窗異步關(guān)閉操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11
Vue?Echarts實(shí)現(xiàn)帶滾動(dòng)效果的柱形圖
這篇文章主要為大家詳細(xì)介紹了Vue?Echarts實(shí)現(xiàn)帶滾動(dòng)效果的柱形圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
vue3+ts 兄弟組件之間傳值的實(shí)現(xiàn)
Vue3是一款流行的前端框架,它支持多種傳值方式,包括兄弟組件之間的傳值,本文主要介紹了vue3+ts 兄弟組件之間傳值的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11

