Vue2 使用的是 Object.defineProperty Vue3 使用的是 Proxy
对象只能劫持 设置好的数据,新增的数据需要Vue.Set(xxx) 数组只能操作七种方法,修改某一项值无法劫持。
export const reactive = (target:T) => {
return new Proxy(target,{
get (target,key,receiver) {
const res = Reflect.get(target,key,receiver) as object
return res
},
set (target,key,value,receiver) {
const res = Reflect.set(target,key,value,receiver)
return res
}
})
}
Vue3 的响应式原理依赖了 Proxy 这个核心 API,通过 Proxy 可以劫持对象的某些操作。
实现effect 副作用函数
let activeEffect;
export const effect = (fn:Function) => {
const _effect = function () {
activeEffect = _effect;
fn()
}
_effect()
}
使用一个全局变量 active 收集当前副作用函数,并且初始化的时候调用一下
实现track
const targetMap = new WeakMap()
export const track = (target,key) =>{
let depsMap = targetMap.get(target)
if(!depsMap){
depsMap = new Map()
targetMap.set(target,depsMap)
}
let deps = depsMap.get(key)
if(!deps){
deps = new Set()
depsMap.set(key,deps)
}
deps.add(activeEffect)
}
执行完成成后我们得到一个如下的数据结构
实现trigger
export const trigger = (target,key) => {
const depsMap = targetMap.get(target)
const deps = depsMap.get(key)
deps.forEach(effect=>effect())
}
当我们进行赋值的时候会调用 set 然后 触发收集的副作用函数
import {track,trigger} from './effect'
export const reactive = (target:T) => {
return new Proxy(target,{
get (target,key,receiver) {
const res = Reflect.get(target,key,receiver) as object
track(target,key)
return res
},
set (target,key,value,receiver) {
const res = Reflect.set(target,key,value,receiver)
trigger(target,key)
return res
}
})
}
给 reactive 添加这两个方法
Document
import { track, trigger } from './effect'
const isObject = (target) => target != null && typeof target == 'object'
export const reactive = (target: T) => {
return new Proxy(target, {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver) as object
track(target, key)
if (isObject(res)) {
return reactive(res)
}
return res
},
set(target, key, value, receiver) {
const res = Reflect.set(target, key, value, receiver)
trigger(target, key)
return res
}
})
}
Document