vue3的mvvm實現原理是基於Proxy實現的,可比vue2的Object.defineProperty簡明扼要不少,也很巧妙,demo不難,一步步實現吧,總共就一個js文件,不超過100行代碼,要什麼自行車。vue
更新視圖的方法react
把數據變爲響應式數據的方法數組
測試數據緩存
改變測試數據 觸發更新視圖方法框架
// 用最簡化的模型來模式vue3的mvvm實現原理
// 用這個方法來模式視圖更新
function updateView() {
console.log('觸發視圖更新啦')
}
// 把原目標對象 轉變 爲響應式的對象
function reactive(target) {
// todo 具體如何轉變,以及綁定視圖更新方法
let proxyed = new Proxy(target, options)
return proxyed
}
// 測試數據
let obj = {
name: 'Ace7523',
array: ['a', 'b', 'c']
}
// 把原數據轉變響應式的數據
let reactivedObj = reactive(obj)
// 改變數據,指望會觸發updateView() 方法 從而更新視圖
reactivedObj.name = 'change'
複製代碼
小結 準備工做算是作完了,接下來就是實現reactive方法,而後修改一下obj對象,看是否會觸發updateView()方法mvvm
利用 new Proxy(target, options) 對target對象,進行數據改造測試
完善 optionsspa
// 用最簡化的模型來模式vue3的mvvm實現原理
// 用這個方法來模式視圖更新
function updateView() {
console.log('觸發視圖更新啦')
}
// 把原目標對象 轉變 爲響應式的對象
const options = {
set(target, key, value, reciver) {
updateView()
return Reflect.set(target, key, value, reciver)
},
get(target, key, reciver) {
return Reflect.get(target, key, reciver)
},
deleteProperty(target, key) {
return Reflect.deleteProperty(target, key)
}
}
function reactive(target) {
// todo 具體如何轉變,以及綁定視圖更新方法
let proxyed = new Proxy(target, options)
return proxyed
}
// 測試數據
let obj = {
name: 'Ace7523',
array: ['a', 'b', 'c']
}
// 把原數據轉變響應式的數據
let reactivedObj = reactive(obj)
// 改變數據,指望會觸發updateView() 方法 從而更新視圖
reactivedObj.name = 'change'
複製代碼
小結 其實本質上就是不用Object.defineProperty 而改用別的方式來重寫對象的get set方法了,也就是Proxy 的方式代理
添加的代碼以下isObject()方法判斷是不是對象,修改options.get()code
function isObject(t) {
return typeof t === 'object' && t !== null
}
// 把原目標對象 轉變 爲響應式的對象
const options = {
set(target, key, value, reciver) {
updateView()
return Reflect.set(target, key, value, reciver)
},
get(target, key, reciver) {
const res = Reflect.get(target, key, reciver)
if(isObject(target[key])){
return reactive(res)
}
return res
},
deleteProperty(target, key) {
return Reflect.deleteProperty(target, key)
}
}
複製代碼
小結 這裏比較巧妙,建議對比下vue2中的Object.defineProperty的方法對比着看。
防止對數組添加數據時候,重複觸發更新視圖的方法
利用weakMap 記錄原數據是否進行過代理,若是代理過,則返回記錄值,再也不重複代理
// 用最簡化的模型來模式vue3的mvvm實現原理
// 用這個方法來模式視圖更新
function updateView() {
console.log('觸發視圖更新啦')
}
function isObject(t) {
return typeof t === 'object' && t !== null
}
// 把原目標對象 轉變 爲響應式的對象
const options = {
set(target, key, value, reciver) {
if(target.hasOwnProperty(key)){
updateView()
}
return Reflect.set(target, key, value, reciver)
},
get(target, key, reciver) {
const res = Reflect.get(target, key, reciver)
if(isObject(target[key])){
return reactive(res)
}
return res
},
deleteProperty(target, key) {
return Reflect.deleteProperty(target, key)
}
}
// 用來作緩存
const toProxy = new WeakMap()
function reactive(target) {
if(!isObject(target)){
return target
}
// 若是已經代理過了這個對象,則直接返回代理後的結果便可
if(toProxy.get(target)){
return toProxy.get(target)
}
let proxyed = new Proxy(target, options)
toProxy.set(target, proxyed)
return proxyed
}
// 測試數據
let obj = {
name: 'Ace7523',
array: ['a', 'b', 'c']
}
// 把原數據轉變響應式的數據
let reactivedObj = reactive(obj)
// 改變數據,指望會觸發updateView() 方法 從而更新視圖
reactivedObj.name = 'change'
複製代碼
小結 完整版代碼暫時就這麼多,沒有考慮過多的邊界條件,感興趣的朋友能夠複製出來玩玩看,改改測試數據看看會不會觸發更新視圖的方法~~~