浅谈对Vue响应式的理解

339 阅读1分钟

什么是Vue响应式?

官网解释:

Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。

简而言之就是数据改变时,页面也会改变。

实现原理

Vue在组件和实例初始化的时候,会将data里的数据进行数据劫持(object.definepropty对数据做处理)。被解除过后的数据会有两个属性:一个叫getter,一个叫setter。

Vue2通过Object.defineProperty来实现数据响应式

Object.defineProperty

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

语法:Object.defineProperty(obj, prop, descriptor)

参数:

obj:要定义的对象

prop:要定义或修改的属性的名称或者symbol

descriptor:要定义或修改的属性描述符

// 例一:用 Object.defineProperty 定义 n
let data1 = {}
Object.defineProperty(data1, 'n', {
	value: 0
})
console.log(`需求一:${data1.n}`)

总之:

  1. Object.defineProperty可以给对象添加属性value
  2. Object.defineProperty可以给对象添加getter/setter
  3. getter/setter用于对属性的读写进行监控

Vue.set、this.$set

Vue存在bug,当Object.defineProperty(obj,'n',{…})时,必须要有一个'n'才能监听&代理obj.n,如果不给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; //请问,页面中会显示 1 吗?
		    }
		  }
}).$mount("#app");

点击button按钮,页面上并不会出现1,因为vue不会监听一开始不存在的obj.b

如何解决?

1.声明好key再加属性 2.使用Vue.set或者this.$set,他们的作用是新增key,自动创建代理和监听(如果没有创建过),自动触发UI更新(并不会立刻更新)

setB() {
	this.$set(this.obj,'b' , 1) //写法一
        Vue.set(this.obj,'b' , 1); //写法二
    }

如果data里有数组时没法提前声明所有key,当要向数组插入元素时,可以使用Vue.set或this.$set。

但是使用Vue.set或this.$set 作用于数组时,并不会自动添加监听和代理

因此,尤雨溪篡改了数组的API:push()、pop()、shift()、unshift()、splice()、sort()、reverse(),即数组的变异方法。这样就能很方便的修改了。