《Vue的数据响应式》

126 阅读2分钟

数据响应式举例个来说就是,一个物体对于外界的刺激能够做出相应的反应。使用 Vue进行开发时,一旦页面上的数据在 JS内进行了跟新,不需要开发者修改渲染的代码,Vue会自动进行跟新。

这是因为Vue在实例化声明数据时进行了监听和代理,若数据发生了改变,会监听到变化对此进行重新渲染。

Vue如何实现数据响应式

当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。 这个getter/setter对于用户是不可见的,但在内部它们让Vue能够追踪依赖,在 property 被访问和修改时通知变更。

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

举例代码如上,通过Object.defineProperty()将a的数据转为 getter/setter。若是要对data内声明的数据进行更改。现实实例vm就是data的代理,通过vm可以更改data。

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

注意事项

由于JS的限制,Vue对于数组和对象的变化的检查有些问题。

关于对象

  • 示例一
new Vue({
  data: {},
  template: `
    <div>{{n}}</div>
  `
}).$mount("#app");

n不存在,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; 
    }
  }
}).$mount("#app");

页面中点击按钮不会出现1,这是因为Vue只会检查第一次属性。

解决方法:

1.在obj内声明b

2.使用Vue.set()/this.$set()

methods:{
      setB(){
	Vue.set(obj, 'b', 2)
	// this.$set(this.obj,'b',2)
  }
}

关于数组

Vue不能检测以下数组变动

1.利用索引直接设置一个数组项

2.修改数组长度

var vm = new Vue({
  data: {
    items: ['a', 'b', 'c']
  }
})
vm.items[1] = 'x' // 不响应
vm.items.length = 2 // 不响应

解决方法:

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

当数据中含有数组时,若要给数组添加元素,但新增元素的index在声明实例的时候还未定义,为了解决这个问题,Vue的作者将数组的七个方法进行了变更。对Array()函数通过继承,增加了一条原型链的环节,并在环节中添加了七种方法,方法的内部进行了Vue.set()的操作,使的数组的新元素能被实例化。

变更方法

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

参考来自 Vue文档——深入响应式原理