简单实现Vue3.x响应式
实现原理:
- 用过Proxy(代理):拦截对象中任意属性的变化,包括:属性值的读写,属性的添加、属性的删除等
- 通过Reflect (反射) :对被代理对象的属性进行操作
直接上代码
注意:通过Proxy代理实现的响应式,可以在set中,捕捉到对象的设置,
在deleteProperty中捕捉到对象属性的删除,即完成对象响应式操作
const targetMap = new WeakMap() // 保存对象的变量
function track(target,key){
// 如果此时activeEffect为null则不执行下面
// 这里判断是为了避免例如console.log(person.name)而触发track
if(!activeEffect) return
let depMap = targetMap.get(target) // 保存对象属性的变量
if(!depMap) targetMap.set(target,depMap = new Map())
let dep = depMap.get(key) // 保存每个属性的依赖
if(!dep) depMap.set(key,dep = new Set())
dep.add(activeEffect) // 添加属性依赖函数,每次track时加入
}
function trigger(target,key){
const depMap = targetMap.get(target)
const dep = depMap?.get(key)
if(dep) dep.forEach(item=>item()) // 每次触发属性依赖时更新视图
}
function reactive(target){
const handler = {
get(target,key,receiver){
track(receiver,key) // 访问时收集依赖
return Reflect.get(target,key,receiver)
},
set(target,key,newValue,receiver){
Reflect.set(target,key,newValue,receiver)
trigger(receiver,key) // 属性变更时,更新视图
},
deleteProperty(target,key){
Reflect.deleteProperty(target,key)
trigger(target,key) // 删除对应属性的依赖随后更新视图
}
}
return new Proxy(target,handler)
}
// 用来全局保存依赖函数
let activeEffect = null
function effect(fn){
activeEffect = fn
activeEffect()
activeEffect = null
}
function ref(initValue){
return reactive({value:initValue})
}
function computed(fn){
const result = ref()
effect(()=>{result.value = fn()})
return result
}
代码测试:
let person = {name:'孙悟空',age:222}
let obj2 = {animal:'迪丽热吗',height:28}
let myself = '' ,myself2 = '' ,myself3 = '',myself4 = ''
const effect1 = ()=>{myself = `我的名字是${person.name}`}
const effect2 = ()=>{myself2 = `我今年二二二${person.age}岁了`}
const effect3 = ()=>{myself3 = `狗狗狗${obj2.animal}岁了`}
const effect4 = ()=>{myself4 = `二二狗狗古${obj2.height}岁了`}
person = reactive(person)
obj2 = reactive(obj2)
effect(effect1)
effect(effect2)
effect(effect3)
effect(effect4)
console.log(myself);
console.log(myself2);
console.log(myself3);
console.log(myself4);
看看输出结果:
直接更改数据,并达到响应式:
let person = {name:'孙悟空',age:222}
let obj2 = {animal:'迪丽热吗',height:28}
let myself = '' ,myself2 = '' ,myself3 = '',myself4 = ''
const effect1 = ()=>{myself = `我的名字是${person.name}`}
const effect2 = ()=>{myself2 = `我今年二二二${person.age}岁了`}
const effect3 = ()=>{myself3 = `狗狗狗${obj2.animal}岁了`}
const effect4 = ()=>{myself4 = `二二狗狗古${obj2.height}岁了`}
person = reactive(person)
obj2 = reactive(obj2)
effect(effect1)
effect(effect2)
effect(effect3)
effect(effect4)
// 直接修改数据,响应式更新视图
person.name = 'cmr' ,person.age = 22
obj2.animal = '啊啊啊四点九四哦',obj2.height = 78
console.log(myself);
console.log(myself2);
console.log(myself3);
console.log(myself4);
测试ref
// 测试ref
let num = ref(5)
console.log(num.value);
effect(()=>{sum = num.value * 100})
console.log(sum); // 500
测试computed
//测试computed
let num1 = ref(5)
let num2 = ref(8)
let sum1 = computed(() => num1.value * num2.value)
let sum2 = computed(() => sum1.value * 10)
console.log(sum1.value) // 40
console.log(sum2.value) // 400
num1.value = 10
console.log(sum1.value) // 80
console.log(sum2.value) // 800
num2.value = 16
console.log(sum1.value) // 160
console.log(sum2.value) // 1600