解决Vue修改数组/字典中的元素,却无法检测到数据变化的问题
一 背景
我在做毕设的项目中,写前端逻辑代码时遇到了一个问题:通过用户click触发一个函数,在函数中根据选中的index,动态修改Map容器中的对应下标的值,以此用不同的class来凸显用户的选择项。实现目标效果图如下图(解决了本篇所要解决的问题后):
{width=”50%”}
二 实现思路
先说下实现这种样子的思路,首先我在设计后端API的时候,要注意返回的Json数据格式,每一个商品都会有多个sku属性,每个sku属性都会对应多个sku属性值,因此这样关系很清晰,通过1:N外键关系就可以表示。格式如下:
1 |
|
这样,我在vue中通过v-for两次循环遍历即可表示出多个sku属性,每个属性下对应多个sku属性值。
那么接下来的需求就是用户选择每个sku属性下的属性值,我需要记录下来并高亮标注显示给用户,因此我是采用字典,姑且取个名字,choiceMap,其中key为每个属性的名字,value为选中的值的下标。当用户选择了某项时,choiceMap中对应key的value的下标变化成选中的属性值的下标,然后在template中使用,:class,通过表达式(判断choiceMap[key] === index)是否为真,来增加/消除颜色高亮风格的class。对应代码如下:
1 |
|
说明:点击某个属性值,调用choiceValue(index, values)
来实现高亮显示。我一开始使用的方式是:
1 |
|
通过控制台打印发现,数据确实更新了,但是view视图却没有更新,后来我测试了一下数组,发现同样的问题。由于鄙人前端没有深入,因此只得百度搜索解决方案,幸运的是很快找到了解决方法,在仔细阅读别人的博客后,发现了问题所在—–Vue不能检测到对象的添加或者删除。然而Vue在初始化实例时就对属性执行了setter/getter转化过程,所以属性必须开始就在对象上,这样才能让Vue转化它。 这句话什么意思呢?别急,我用几个解释以下:
1 |
|
结果:view视图随着test方法的调用会发生变化,name属性会改变,同时hobby属性也会添加进来,dom元素能够及时响应并更新。
1 |
|
结果:view视图随着test方法的调用不会发生变化,数据会发生变化,但是dom元素并未更新,没有得到响应。
分析:根据上面两个例子,再结合 **”Vue不能检测到对象的添加或者删除。然而Vue在初始化实例时就对属性执行了setter/getter转化过程,所以属性必须开始就在对象上,这样才能让Vue转化它”**这句话来看,由于第一个例子中name属性在vue实例化时就已经执行转化过程,那么后续对访问器的属性进行操作时,会调用响应的方法,例如读取属性值,会调用getter方法,在修改属性值时会调用setter的方法,这样这些方法就会在底层来决定如何更新数据,包括更新DOM。以此来实现单向绑定及双向绑定。
三 解决方案
为了能够对未经初始化,为执行setter/getter转化过程的属性修改,同时确保这些属性被创建后是响应式的,触发视图view的更新,可以使用Vue.set(Object, String, Any)方法,它的用法是设置对象的属性,如果该对象在data中定义为响应对象,那么该方法确保该对象的属性被创建后也是响应式的,同时触发视图更新。这个方法就可以避开Vue不能检测属性被添加的限制。
{width=”100%”}
所以代码更正为:
1 |
|
恕我前端不够深入, 推荐一篇讲的更加详细的文章,如有兴趣,可以前去浏览
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!