Vue数据响应式的理解

1,189 阅读2分钟

在使用Vue进行开发时,一旦页面上展示的数据在js中进行了更新,那么并不需要开发者编写有关渲染的代码,vue会自动将页面对应的数据更新。因为vue底层对实例化时声明的数据(属性)都进行了监听和代理,即当数据变化时,Vue会立刻监听到变化,并调用渲染操作。

Vue是如何实现数据响应式的

当我们创建Vue实例时,将数据传入Vue(),Vue底层会将传进来的数据进行“包装”,

let vm = new Vue({
  data: {
    obj: {
      a: 0 
    }
  }
})

拿以上代码举例,会通过Object.defineProperty()将a用一个含getter/setter的虚拟属性替代,这样就实现对a数据的读写和监听。 再通过在data外层包裹一层代理(一层包含getter/setter虚拟属性的对象),实现实例对象vmdata的代理。即必须通过vm更改data内已声明的数据。

vm.obj.a = 2 //可以更改
this.obj.a =2 //可以更改
this.data.obj.a =2 //不可以更改

Vue中data属性的一个特性

当我们以普通的方式增添新数据(实例化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; //页面中不会渲染出b值,因为b未被Vue监听
    }
  }
}).$mount("#app");

此时有两种解决办法:

  • 在obj中声明一下b
  • 使用 Vue.set() / this.$set()
 methods: {
    setB() {
      Vue.set(obj,"b",1)
    }
  }

所以当数据中含有数组时,当我们想为数组添加元素时,新增元素的index在声明实例时未定义,也会面临相同的情况(数组是一种特殊的对象,property为数字的对象)。此时我们也应该采取一些措施,好在vue的作者为我们将数组的七种方法进行了变异,这七种方法分别是

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

具体的方式大概是作者为Array()函数通过继承,新增了一条原型链环节,在该环节中添加了上述七种方法,并方法内部进行了Vue.set()方法的操作,使数组的新元素可以被vue实例对象监听和代理。