什么是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}`)
总之:
Object.defineProperty可以给对象添加属性valueObject.defineProperty可以给对象添加getter/settergetter/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(),即数组的变异方法。这样就能很方便的修改了。