Vue数据响应式

167 阅读1分钟

一、Vue的data是响应式的。

const vm = new Vue({data : {n : 0}})

上述代码,如果修改vm.n,那么UI中的n就会响应。Vue通过Object.defineProperty来实现数据响应式。

二、Vue的bug

1. Object.defineProperty的问题

Object.defineProperty(obj , 'n' , {...})中必须要有一个'n'才能监听和代理obj.n,如果没给n,Vue会报错,但Vue只会检查第一层属性,有多层的话警告会消除,但不会转为响应式,因为Vue无法监听不存在的数据。如:

new Vue({
  data: {
    obj: {
      a: 0 // obj.a 会被 Vue 监听 & 代理
    }
  },
  template: `
    <div>
      {{obj.b}}
      <button @click="setB">set b</button>
    </div>
  `,
  methods: {
    setB() {
      this.obj.b = 1; //此时虽然不报错,但页面中不会显示1
    }
  }
}).$mount("#app");

此种情况有两种解决方法:

  • key都声明好,后面不再加属性即可:

  • 使用Vue.set或者this.$set新增Key、自动创建代理和监听并触发UI更新:

2. 如果data中有数组,你无法提前声明所有key

数组的长度可以一直增加,下标就是key,难道每次改数组都要用Vue.set或者this.$set(而且用Vue.setthis.$set不会创建代理和监听)?Vue有法子

Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

举例:

new Vue({
  data: {
    array: ["a", "b", "c"]
  },
  template: `
    <div>
      {{array}}
      <button @click="setD">set d</button>
    </div>
  `,
  methods: {
    setD() {
      this.array.push("d") //变异API
      console.log(this.array);
    }
  }
}).$mount("#app");