响应式系统要实现的是:另一群数据根据他们所依赖的响应式数据改变。
举例:
设一个视图层的属性innerText="我还好",数据层的响应式属性a="我还好",innerText依赖于a,当a变为"我不好"时,视图层innerText的值也要跟着改变为"我不好"。
我们就直接想到,可以对a的属性变化进行拦截,用到ES6语法proxy来完成。
// 创建响应式数据a,视图层的属性innerText
document.div.innerText = "我还好"
const a = new Proxy({ value: "我还好" }, {
//当a改变时,a改变的行为会被中止,并触发set函数
set: function (obj, key, newVal) {
// 继续被中止的行为
obj[key] = newVal
// 令视图层属性 innerText = a ,我们设一个effect()来完成这件事
effect()
return true
})
那问题来了,effect()怎么来的呢?
我们可以想象每个响应式属性a有个桶,当页面初始化读取这个数据时,我们把effect()放进桶里,等改变它的时候,我们再取出来用。那么代码就变成了下面的样子。
document.div.innerText = "我还好"
/// 创建一个不会重复的桶
let buk = new Set()
// 我们的effect函数
function effect() {
document.div.innerText = a.value
}
const a = new Proxy({ value: "我还好" }, {
get: function (obj, key) {
// 桶里塞入effect()
buk.add(effect)
return obj[key]
},
set: function (obj, key, newVal) {
obj[key] = newVal
// 从桶里取出的effect()
buk.forEach((fn) => fn())
return true
},
})
/*完成封装开始运行*/
// 视图层获取其数据触发get将其副作用函数装进桶里
effect()
// 更改响应式数据 a 的值
setTimeout(() => {
a.value = "我不好"
console.log(doc) // 控制台打印 "我不好"
}, 1000)