Vue2?響應(yīng)式系統(tǒng)之深度響應(yīng)
1、場景
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)在還沒有支持屬性是對象時候的響應(yīng),因此我們改變 的時候不會有任何輸出。childText
我們只收集了 的依賴,所以如果想要響應(yīng)的話必須給 整個賦值為一個新對象。data.text
data.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", }, };
我們當然不希望每次都賦值整個對象,我們需要做一些修改,把嵌套的對象也變成響應(yīng)式的。
2、方案
我們只需要在給某個 重寫 和 之前,把它的 就像上邊給 調(diào)用 函數(shù)一樣,也調(diào)用一次 函數(shù)即可。key
get
set
value
data
observe
observe
同時提供 參數(shù),留下擴展,讓外界決定是否需要深度響應(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 沒有傳進來話進行手動賦值 if ((!getter || setter) && arguments.length === 2) { val = obj[key]; } const dep = new Dep(); // 持有一個 Dep 對象,用來保存所有依賴于該變量的 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ù)中,傳進來的 不是對象的話我們直接 。observe
value
return
/* 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、場景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";
可以一分鐘想一下上邊會輸出什么。
new Watcher(updateComponent);
,執(zhí)行一次 輸出 。updateComponent
hello
data.text.innerText.childText = "liang";
,我們已經(jīng)解決了屬性是對象的情況,因此這里也會輸出 。liang
data.text = { innerText: { childText: "liang2", }, };
上邊代碼就是文章最開頭的方法,因此也會觸發(fā)函數(shù)執(zhí)行,輸出 。liang2
data.text.innerText.childText = "liang3";
最后這句會執(zhí)行嗎?
答案是否定的了,因為我們的 賦值為了一個新對象,但這個新對象我們并沒有將其設(shè)置為響應(yīng)式的。data.text
因此我們需要在 的時候把對象也設(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 沒有傳進來話進行手動賦值 if ((!getter || setter) && arguments.length === 2) { val = obj[key]; } const dep = new Dep(); // 持有一個 Dep 對象,用來保存所有依賴于該變量的 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é)
通過遞歸解決了屬性是對象的依賴,可以為未來數(shù)組的依賴留下基礎(chǔ)。
到此這篇關(guān)于Vue2 響應(yīng)式系統(tǒng)之深度響應(yīng)的文章就介紹到這了,更多相關(guān)Vue2 深度響應(yīng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
defineProperty和Proxy基礎(chǔ)功能及性能對比
這篇文章主要為大家介紹了defineProperty和Proxy基礎(chǔ)功能及性能對比,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08vue路由 遍歷生成復(fù)數(shù)router-link的例子
今天小編就為大家分享一篇vue路由 遍歷生成復(fù)數(shù)router-link的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-10-10vue計算屬性無法監(jiān)聽到數(shù)組內(nèi)部變化的解決方案
今天小編就為大家分享一篇vue計算屬性無法監(jiān)聽到數(shù)組內(nèi)部變化的解決方案,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11vue uniapp 防止按鈕多次點擊的三種實現(xiàn)方式
最近的項目完成后,在性能優(yōu)化階段需要做按鈕的防止重復(fù)點擊功能,本文主要介紹了vue uniapp 防止按鈕多次點擊的三種實現(xiàn)方式,具有一定的參考價值,感興趣的可以了解一下2023-08-08基于Vue的SPA動態(tài)修改頁面title的方法(推薦)
這篇文章主要介紹了基于Vue的SPA動態(tài)修改頁面title的方法,需要的朋友可以參考下2018-01-01