在使用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虚拟属性的对象),实现实例对象vm对data的代理。即必须通过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实例对象监听和代理。