
今天让我们实现一下「vue」响应式的原理
❝❞
- 响应式数据通过内部的defineReactive函数实现响应式数据更新,defineReactive核心是defineProperty对每个属性进行监听
- 每个属性都定义一个dep 空数组在第一次执行更新函数时候调用get方法时候收集依赖(不能每次都进行收集,所以更新函数需要第一次放入watch进行订阅,要设置了active,在watch的时候,active设置为true即可,执行更新函数fn,把active设置为false)
- 在set的时候触发依赖执行更新函数
- 把更新函数放入watch 函数内进行触发更新。
1 核心defineReactive
- 响应式数据通过内部的defineReactive函数实现响应式数据更新,
- defineReactive核心是「defineProperty」对每个属性进行监听
function defineReactive(obj) {
for (let key in obj) {
let value = obj[key]
Object.defineProperty(obj, key, {
get() {
return value
},
set(newValue) {
value = newValue
}
})
}
}
defineReactive(state) // 执行一下 变成响应式的
2 在get中对dep进行收集依赖
- 循环对象的每个属性都定义一个dep 空数组
- 在「第一次」执行更新函数fn时候调用「get」方法时候收集依赖
- 不能每次都进行收集,所以更新函数需要第一次放入watch进行订阅,要设置了active,在watch的时候,active设置为true即可,执行更新函数fn,把active设置为false(第4步说到)
let active
for (let key in obj) {
let dep = []
Object.defineProperty(obj, key, {
get() {
if (active) {
dep.push(active)
}
},
})
}
3 set的时候发布
- 在set的时候触发依赖执行更新函数
set(newValue) {
value = newValue
dep.forEach(fn => fn())
}
4 watch 观察者
- 定义一个watch函数
- 把更新函数fn都放入watch 函数内进行触发更新。
let watch = (fn) => {
active = fn
fn()
active = null
}
watch(() => {
app.innerHTML = state.count
})
watch(() => {
console.log(state.count)
})
5 代码合集
let state = { count: 1 }
let active
// 把数据变成响应式
function defineReactive(obj) {
for (let key in obj) {
let value = obj[key]
let dep = []
Object.defineProperty(obj, key, {
get() {
if (active) {
dep.push(active)
}
return value
},
set(newValue) {
value = newValue
dep.forEach(fn => fn())
}
})
}
}
defineReactive(state) // 执行一下 变成响应式的
let watch = (fn) => {
active = fn
fn()
active = null
}
watch(() => {
app.innerHTML = state.count
})
watch(() => {
console.log(state.count)
})
setTimeout(() => {
state.count = 2 //测试两秒后是否触发响应
}, 3000)
本文使用 mdnice 排版