Vue data中属性不响应及解决方法
现在vue框架用起来虽然很方便,很爽,但是难免也会遇到一些问题,其中新手遇到的data属性更改了但却没有刷新界面,即不响应的问题是比较烦人的,下面我就介绍一下,为vue新手的起步之路扫除一个障碍🙂。
给vue实例添加属性一般有两种方式。
-
直接写在data里面
data() {
return {
name:''
}
}
-
data中没有age属性
vm.age = 26
对于这两种情况,第一种的name
是响应的,而第二种的age
无法响应。为什么呢,我们再解释下是否响应是怎么来的,即vue给属性添加响应关系的过程是怎样的。
vue会在vue实例初始化的时候对
data
中的属性执行getter/setter
转化过程,所以属性必须在data
对象上存在才能让 Vue 转换它。
很明显,第二种的age
错过了添加getter/setter
转化的时机,所以无法响应。
不过我相信大多数人遇到问题的都不是这种,而是第一例的另一种情况,我直接上部分代码:
data() {
return {
person:{}
}
},
methods:{
btnPressed():{
this.person.name = '张三'
}
}
这种情况的话,person
的name
确实是被改成了'张三'
,相信你也log
了好几次,但是为什么界面上就是没有更改呢,原因刚才已经说过了,因为这里的name
并未添加getter/setter
的监测方法,即无法响应,当这个name
的值改变的时候,界面上无法进行相应的更改,那有些人可能会说我这个person
不是响应的吗?
没错,person
是响应的,但这里的person
是个对象,对person
添加getter/setter
转化方法时,person
还没有name
这个字段,所以person
可以响应,而person.name
无法响应。
推测
data
中的对象类型的属性,如果在data
中已写出,就会被添加getter/setter
方法进行响应式监测处理,而没有写的则不会,查了很多资料,好像也确实是这个道理,如以下这个例子。
<template>
<div id="app">
<div>{{person.name}}</div>
<div>{{person.age}}</div>
<button @click="btnPressed">点击</button>
</div>
</template>
<script>
export default {
name: 'app',
data(){
return {
person:{name:''}
}
},
created(){
this.person.name = 'liu'
this.person.age = '100'
},
methods:{
btnPressed(){
this.person.name = 'zhao'
this.person.age = '200'
}
}
}
</script>
根据推测,界面上应该一开始出现'liu'
和'100'
两行,但是点击了按钮执行btnPressed
之后,第一行会变为'zhao'
,而第二行不变,还是'100'
。
但是!!结果两个值都变了,第二行也变为了'200'
,之后我又加了各种属性,gender
,father
等,依然都跟着改变,只要person
中有其中一个初始值,它的所有属性就都会变成响应式;
然而,将person
的属性key
由'name'改为'names',那么这里的name
和age
都不会被改变,也就是后面我修改的任意属性值又不是响应式了......不信的可以试试,我这里还没有理解😅,求大神给解释。
解决方案
这里首先给出官方的解决方案:
this.$set(this.person,'name','zhao')
这句话加上之后如果this.person
的name
属性没有setter/getter
响应方法,则会添加上,属性为响应式。你可能以为这样就可以了,然而事实还是在执行方法时name属性没有改变🤔,因为我们是把它放在按钮点击方法里的,所以最开始不会执行这个地方,我们找找。
问题在这里
created(){
this.person.name = 'liu'
this.person.age = '100'
},
由于这里是第一次给person
添加name
属性,也没有使用$set
方法,所以name
这里没有setter
和getter
方法,而后面再用$set
方法的时候,由于name
属性已存在了,所以$set
方法不会再进行setter/getter
方法进行响应式监测,这里一定要注意。
结论:
还是要细读官方文档,vue作者已经在其中推荐尽量在data
初始化中将需要用到的属性都写出来,这样便于维护且可读性更好。
如果data
中某属性对应初始值为{}
,且依然想要添加响应式属性的话,用以下方法:
this.$set(this.objectProperty,'key',value)