现在我们知道了,Vue对data的所有属性进行了监控和代理,使得,对data的属性的更改,vm都要知道。知道了,就会对UI进行渲染。
那到底什么是数据响应式呢?
首先,什么是响应?
我打你一拳,你会喊疼,这就是响应。你就是响应式的。也就是说,外界在你身上做了操作,你能作出反应,那就是响应式的。
Vue的data就是响应式的
因为 const vm=new Vue({data{n:0}})之后,我不管是用this.n 还是myData.n修改,UI视图中的n就会跟着改变,就会响应我。这就是数据响应式。
Vue是通过Object.defineProperty 来实现数据响应式的。
响应式网页就是如果我改变窗口大小,网页内容会作出响应。
Vue的data有一个bug
Vue是使用Object.defineProperty来监听并且代理data的
Object.defineProperty(obj,'n',(...)
就是说,必须给我一个'n'这个属性,我才能对n监听然后代理。
那如果程序员在一开始没有给n ,该怎么办
示例1

说明,一个没有定义的数据是不能使用的。
示例2
既然警告说,你要渲染的数据没定义,我没找到。那我就绕过这个问题,定义一个:
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");
首先:data里又嵌套了一层obj,我定义了obj.a。于是Vue就会监听&代理obj.a。(和obj,我写的都会监听)
但是,我在template里要渲染的是obj.b。虽然obj.b还是没有定义,却没有警告了。因为Vue要渲染的时候,只会检查第一层。看到obj定义了,就不会再往里检查了。
我通过这种方法绕过了警告
点击按钮,会把this.obj.b赋值为1。那么页面会显示1吗?结果是不会。
因为定义的是obj.a,所以Vue只会监听你给的属性。obj里有什么属性,就监听什么属性。没有b,当然就不会监听b了。给obj.b赋值的操作,Vue当然也就不会知道了。不知道当然就没办法响应了。
这个就是bug。这个bug是由Object.defineProperty带来的。因为使用它就必须有一个属性,比如n。所以,如果我一开始没定义某个属性,该属性就不会被监听,那我之后要改变它的时候,就无法更新了。
解决方法:
- 我一开始定义一个b不就好了,只是不给值而已
这样点击按钮,会显示1.data: { obj: { a: 0 ,// obj.a 会被 Vue 监听 & 代理 b:undefined } },
但是,有些人也不会提前写,就导致之后在赋值的时候说页面没更新。
-
使用Vue.set 或 this.$set
setB() { Vue.set(this.obj, "b", 1); }如果想赋值,发现一开始没有定义这个属性。就可以使用Vue.set()。
Vue.set做了什么?
首先,当然是在data.obj里新增了一个属性b,值是1.
然后,自动为obj.b创建监听和代理。就像Object.defineProperty做的一样
触发UI更新
之后如果再想改变b的值,因为现在已经监听并且代理了,所以之后直接this.obj.b就可以改变了,并且Vue也能知道,然后渲染到页面中。
data经过了Vue之后,最重要的是监听和代理。所以在实例已经创建的情况下,再为实例添加一个属性不只是单纯赋值那么简单,还要监听和代理,这样Vue才能知道数据的改变并且渲染。
在这里我把obj那层对象删掉了,直接在data下边使用Vue.set。发现报错了。
