自己实现一个响应式数据

262 阅读1分钟

响应式系统要实现的是:另一群数据根据他们所依赖的响应式数据改变。

举例:

设一个视图层的属性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)