Vue2?響應(yīng)式系統(tǒng)之深度響應(yīng)
1、場(chǎng)景
import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
text: {
innerText: {
childText: "hello",
},
},
};
observe(data);
const updateComponent = () => {
console.log(data.text.innerText.childText);
};
new Watcher(updateComponent);
data.text.innerText.childText = "liang";
我們的響應(yīng)式系統(tǒng)到現(xiàn)在還沒(méi)有支持屬性是對(duì)象時(shí)候的響應(yīng),因此我們改變 的時(shí)候不會(huì)有任何輸出。childText
我們只收集了 的依賴,所以如果想要響應(yīng)的話必須給 整個(gè)賦值為一個(gè)新對(duì)象。data.textdata.text
import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
text: {
innerText: {
childText: "hello",
},
},
};
observe(data);
const updateComponent = () => {
console.log(data.text.innerText.childText);
};
new Watcher(updateComponent);
data.text = {
innerText: {
childText: "liang",
},
};

我們當(dāng)然不希望每次都賦值整個(gè)對(duì)象,我們需要做一些修改,把嵌套的對(duì)象也變成響應(yīng)式的。
2、方案
我們只需要在給某個(gè) 重寫(xiě) 和 之前,把它的 就像上邊給 調(diào)用 函數(shù)一樣,也調(diào)用一次 函數(shù)即可。keygetsetvaluedataobserveobserve
同時(shí)提供 參數(shù),留下擴(kuò)展,讓外界決定是否需要深度響應(yīng)。shallow
/*******************新增 shallow*******************/
export function defineReactive(obj, key, val, shallow) {
/****************************************************/
const property = Object.getOwnPropertyDescriptor(obj, key);
// 讀取用戶可能自己定義了的 get、set
const getter = property && property.get;
const setter = property && property.set;
// val 沒(méi)有傳進(jìn)來(lái)話進(jìn)行手動(dòng)賦值
if ((!getter || setter) && arguments.length === 2) {
val = obj[key];
}
const dep = new Dep(); // 持有一個(gè) Dep 對(duì)象,用來(lái)保存所有依賴于該變量的 Watcher
/*******************新增****************************/
!shallow && observe(val);
/******************************************************/
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
const value = getter ? getter.call(obj) : val;
if (Dep.target) {
dep.depend();
}
return value;
},
set: function reactiveSetter(newVal) {
const value = getter ? getter.call(obj) : val;
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
dep.notify();
},
});
}
同時(shí),在 函數(shù)中,傳進(jìn)來(lái)的 不是對(duì)象的話我們直接 。observevaluereturn
/*
util.js
export function isObject(obj) {
return obj !== null && typeof obj === "object";
}
*/
export function observe(value) {
if (!isObject(value)) {
return;
}
let ob = new Observer(value);
return ob;
}
3、場(chǎng)景2
import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
text: {
innerText: {
childText: "hello",
},
},
};
observe(data);
const updateComponent = () => {
console.log(data.text.innerText.childText);
};
new Watcher(updateComponent);
data.text.innerText.childText = "liang";
data.text = {
innerText: {
childText: "liang2",
},
};
data.text.innerText.childText = "liang3";
可以一分鐘想一下上邊會(huì)輸出什么。
new Watcher(updateComponent); ,執(zhí)行一次 輸出 。updateComponenthello
data.text.innerText.childText = "liang"; ,我們已經(jīng)解決了屬性是對(duì)象的情況,因此這里也會(huì)輸出 。liang
data.text = {
innerText: {
childText: "liang2",
},
};
上邊代碼就是文章最開(kāi)頭的方法,因此也會(huì)觸發(fā)函數(shù)執(zhí)行,輸出 。liang2
data.text.innerText.childText = "liang3"; 最后這句會(huì)執(zhí)行嗎?
答案是否定的了,因?yàn)槲覀兊?nbsp;賦值為了一個(gè)新對(duì)象,但這個(gè)新對(duì)象我們并沒(méi)有將其設(shè)置為響應(yīng)式的。data.text
因此我們需要在 的時(shí)候把對(duì)象也設(shè)置為響應(yīng)式的。set
/**
* Define a reactive property on an Object.
*/
export function defineReactive(obj, key, val, shallow) {
const property = Object.getOwnPropertyDescriptor(obj, key);
// 讀取用戶可能自己定義了的 get、set
const getter = property && property.get;
const setter = property && property.set;
// val 沒(méi)有傳進(jìn)來(lái)話進(jìn)行手動(dòng)賦值
if ((!getter || setter) && arguments.length === 2) {
val = obj[key];
}
const dep = new Dep(); // 持有一個(gè) Dep 對(duì)象,用來(lái)保存所有依賴于該變量的 Watcher
let childOb = !shallow && observe(val);
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
const value = getter ? getter.call(obj) : val;
if (Dep.target) {
dep.depend();
}
return value;
},
set: function reactiveSetter(newVal) {
const value = getter ? getter.call(obj) : val;
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
/******新增 *************************/
childOb = !shallow && observe(newVal);
/************************************/
dep.notify();
},
});
}
4、總結(jié)
通過(guò)遞歸解決了屬性是對(duì)象的依賴,可以為未來(lái)數(shù)組的依賴留下基礎(chǔ)。
到此這篇關(guān)于Vue2 響應(yīng)式系統(tǒng)之深度響應(yīng)的文章就介紹到這了,更多相關(guān)Vue2 深度響應(yīng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue項(xiàng)目中實(shí)現(xiàn)el-dialog組件可拖拽效果
本文主要介紹了vue項(xiàng)目中實(shí)現(xiàn)el-dialog組件可拖拽效果,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
vue實(shí)現(xiàn).md文件預(yù)覽功能的兩種方法詳解
這篇文章主要介紹了Vue預(yù)覽.md文件的兩種方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2025-04-04
在Vue中使用動(dòng)態(tài)import()語(yǔ)法動(dòng)態(tài)加載組件
在Vue中,你可以使用動(dòng)態(tài)import()語(yǔ)法來(lái)動(dòng)態(tài)加載組件,動(dòng)態(tài)導(dǎo)入允許你在需要時(shí)異步加載組件,這樣可以提高應(yīng)用程序的初始加載性能,本文給大家介紹在Vue中使用動(dòng)態(tài)import()語(yǔ)法動(dòng)態(tài)加載組件,感興趣的朋友一起看看吧2023-11-11
vuejs2.0運(yùn)用原生js實(shí)現(xiàn)簡(jiǎn)單的拖拽元素功能示例
本篇文章主要介紹了vuejs2.0運(yùn)用原生js實(shí)現(xiàn)簡(jiǎn)單的拖拽元素功能示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-02-02
關(guān)于vue.js彈窗組件的知識(shí)點(diǎn)總結(jié)
最近在開(kāi)發(fā)過(guò)程對(duì)對(duì)于組件化的開(kāi)發(fā)有一些感想,于是開(kāi)始記錄下這些。彈窗組件一直是 web 開(kāi)發(fā)中必備的,使用頻率相當(dāng)高,最常見(jiàn)的莫過(guò)于 alert,confirm和prompt這些,不同的組件庫(kù)對(duì)于彈窗的處理也是不一樣的,下面來(lái)一起看看吧。2016-09-09
Vue實(shí)現(xiàn)訂單支付倒計(jì)時(shí)功能
這篇文章主要給大家介紹了Vue實(shí)現(xiàn)訂單支付倒計(jì)時(shí)功能,倒計(jì)時(shí)這要運(yùn)用在創(chuàng)建訂單后15分鐘內(nèi)進(jìn)行支付,否則訂單取消,本文結(jié)合示例代碼給大家詳細(xì)講解,需要的朋友可以參考下2023-08-08
vue element-ui table組件動(dòng)態(tài)生成表頭和數(shù)據(jù)并修改單元格格式 父子組件通信
這篇文章主要介紹了vue element-ui table組件動(dòng)態(tài)生成表頭和數(shù)據(jù)并修改單元格格式 父子組件通信,需要的朋友可以參考下2019-08-08

