vue 响应式原理模拟5 - 补充

60 阅读1分钟

对于这个简易的 Vue 还有一些问题,比如在实现 v-model 的时候我们还没有实现在输入的同时改变绑定的 data 属性。

双向绑定

这里对于输入框的绑定很简单,监听他的 input 事件,然后修改 data 中的属性为输入框中的值即可:

 modelUpdater (node, value, key) {
    ...
    node.addEventListener('input', () => {
      this.vm[key] = node.value
    })
  }

给 Vue 实例新增一个成员不是响应式的

Vue 类中,给已有的属性重新赋值,那么重新赋值后的属性还是响应式的,这是因为我们给 $data 中属性的 setter 里又执行了 walk 方法。但是直接给 Vue 实例新增一个成员,那么新增的成员不是响应式的。

在我们这个简单的模拟示例中没有给出这个问题的解决方案,但是在 Vue 中,是提出了解决方案的, 使用 Vue.set 或者 vm.$set 方法就可以让新增的成员是响应式的。

data中属性的死循环

我在自己重写一遍代码的过程中,发现最容易错的地方就是在 defineReactive 中将 data 属性转换为 getter/setter 时,直接使用了 data[key],从而导致了死循环。

defineReactive(data, key) {
        let value = data[key]
        Object.defineProperty(data, key, {
            enumerable: true,
            configurable: true,
            // get/set 中都要用 value,而不是 data[key],这里用 data[key] 会造成死循环
            get() {
                return value
            },
            set(newValue) {
                if (newValue === value) return
                value = newValue
            }
        })
    }

由于 data[key]get/set 中用到了 value,所以 defineReactive 就形成了闭包,其中的 value 一直没被销毁,获取 data[key] 的时候直接取了闭包中的 value 值,修改的时候也是直接修改了闭包中 value 的值,所以可以达成修改 value 的值但是作用于 data[key] 的效果。