$set是否是无法刷新视图的万能解决办法?
2017-12-05 本文已影响47人
microkof
前言
目前我在使用vue开发,今天,我遇到了一个怪事:
data上的数据,从{}
到一个多层json,这一步没问题,视图得到了响应,但是,当修改这个多层的json的一个低层的值的时候,注意,并不是新增键,而是只是修改值,结果,死活得不到视图的响应。
见了鬼了?
查了查资料,说是跟“ Vue 无法探测普通的新增属性 ”有关系。然而,我这也不是新增的属性,只是在修改属性,不知道为何同样得不到响应。
教程上说,用this.$set()强制刷新视图即可,那么我就试了试:
我想修改的键是:
this.notebook[cardKey].filter((v) => {
return v.id === noteItemId
})[0].checked
也就是很深的这个checked
,按照手册,我写成了这样:
const thisNoteItem = this.notebook[cardKey].filter((v) => {
return v.id === noteItemId
})[0]
this.$set(thisNoteItem, 'checked', true)
依然不行!
又有资料说,需要用上this.forceUpdate()
,经过测试,依然不行!
原因至今没明白,大约是对象的层级实在是太深,加上还用到了过滤函数,导致问题无法解决。
所以这种情况下,不要给自己找麻烦,深层的数据对象,实在无法刷新视图,就不要认死理,而是可以改变一个思路。
解决方法1
因为通常我们都是修改它的一个底层的值,可能是布尔值也可能是其他具体值,下面例子以布尔值为例,那么,另外用一个对象储存你对布尔值的修改,这个对象我称为“diff对象”,它非常简单,只有一层:
diffObj: {
1: true,
2: false,
...
}
这时候,用this.$set(this.diffObj, noteid, 'checked')
就能正确响应了。
解决方法2
也是构建2个对象,一个叫数据对象,一个叫索引对象。比如,你原本的对象是:
[
{a: [
{
id: 1,
content: 1
},
{
id: 2,
content: 2
}
]}
]
可以看到,低层对象是:
{
id: 1,
content: 1
}
其实这个大对象,就是把低层对象分了组,并且给了组名。
那么我们的办法就是:
- 低层对象先不要分组,全部平级放在一个数组里,这相当于“数据对象”。
- 另外构建一个对象,存放分组,每个分组不再存放低层对象,而是只存放低层对象的索引,这相当于“索引对象”。
- v-for循环也是循环两层,是循环“索引对象”,其中深层循环的是索引,当需要取值,就从“数据对象”中取即可。