vue3中的shallowReactive與reactive是怎么實現的呢?學習自尚硅谷
目的
使一個正常的object對象轉化為響應式對象
解決方案
簡單的說,就是w3c在object的增刪改查時增加了hook函數,可以讓用戶對原生js獲取事件、賦值事件等進行捕捉。這個hook函數就是Proxy與Reflect.
我接下來做的一件事就是使用這個hook函數,來使一個正常的object對象轉化為響應式對象。
嚴格來講,這個最后結果還不是響應式對象,只是這個object再增刪改查屬性的時候會觸發自定義邏輯,具體編寫什么樣的邏輯能能夠做到vue3中的響應式,本文沒有闡述。
可以首先定義一個事件處理函數,對原生js獲取事件、賦值事件等進行捕捉,隨后再傳遞給Reflect
const reactiveHandler = {
get (target, key) {
if (key==='_is_reactive') return true
console.log('數據已獲取');
return Reflect.get(target, key)
},
set (target, key, value) {
const result = Reflect.set(target, key, value)
console.log('數據已更新, 去更新界面')
return result
},
deleteProperty (target, key) {
const result = Reflect.deleteProperty(target, key)
console.log('數據已刪除, 去更新界面')
return result
},
}
然后就可以進行轉化了:
/*
自定義shallowReactive
目的是讓該對象成為一個Proxy對象,方便對一些增刪改查的方法進行攔截並添加自定義邏輯
*/
function shallowReactive(obj) {
return new Proxy(obj, reactiveHandler)
}
/*
自定義reactive
目的是讓該對象,以及該對象內部所有object類型的成員成為一個Proxy對象,方便對一些增刪改查的方法進行攔截並添加自定義邏輯
*/
function reactive (target) {
if (target && typeof target==='object') {
// 內部代碼塊的作用是:
// 1. 遍歷子元素,目的是查看子元素中是否存在object,如果存在再次進入子元素;
// 2. 最終返回一個代理對象Proxy,代理該object
if (target instanceof Array) {
// 檢測到是數組
target.forEach((item, index) => {
target[index] = reactive(item)
})
} else {
// 檢測到是對象
Object.keys(target).forEach(key => {
target[key] = reactive(target[key])
})
}
// 如果這個taraget是一個object,下面的代碼是無論如何都會對這個object執行的
// 換句話說:對每一個子object類型的對象,執行了下面的代碼
const proxy = new Proxy(target, reactiveHandler)
return proxy
}
// 如果不是object,則直接返回
return target
}
console.log('=================測試自定義shallowReactive');
const proxy = shallowReactive({
a: {
b: 3
}
})
proxy.a = {b: 4} // 劫持到了
proxy.a.b = 5 // 沒有劫持到
console.log('=================測試自定義reactive');
/* 測試自定義reactive */
const obj = {
a: 'abc',
b: [{x: 1}],
c: {x: [11]},
}
const proxy2 = reactive(obj)
console.log(proxy2)
proxy2.b[0].x += 1
proxy2.c.x[0] += 1