Vue JS 2 中复杂对象数组的数组更改检测
Posted
技术标签:
【中文标题】Vue JS 2 中复杂对象数组的数组更改检测【英文标题】:Array change detection for an array of complex objects in Vue JS 2 【发布时间】:2018-09-20 18:56:14 【问题描述】:更新
Vue JS 3 会正确处理这个问题:https://blog.cloudboost.io/reactivity-in-vue-js-2-vs-vue-js-3-dcdd0728dcdf
问题:
我有一个看起来像这样的 vue 组件:
sub-comp.vue
<template>
<div>
<input type="text" class="form-control" v-model="textA">
<input type="text" class="form-control" v-model="textB">
<input type="text" class="form-control" v-model="textC">
</div>
</template>
<script>
export default
props:
textA:
type: Number,
required: false
,
textB:
type: Number,
required: false
,
textC:
type: Number,
required: false
</script>
我有一个看起来像这样的父组件:
layout-comp.vue
<template>
<div>
<button @click="addItem">Add</button>
<ul>
<li v-for="listItem in listItems"
:key="listItem.id">
<sub-comp
:textA="listItem.item.textA"
:textB="listItem.item.textB"
:textC="listItem.item.textC"
/>
</li>
</ul>
</div>
</template>
import subComp from '../sub-comp.vue'
export default
components:
subComp
,
data()
return
listItems: []
,
methods:
addItem: function ()
var item =
textA: 5,
textB: 100,
textC: 200
if (!item)
return
this.length += 1;
this.listItems.push(
id: length++,
item: item
);
</script>
问题是,无论我做什么来编辑文本框,数组都不会改变,即使反应数据显示它改变了。例如,它将始终为
textA: 5,
textB: 100,
textC: 200
即使我更改了 textB: 333,listItems 数组仍然显示 textB: 100。这是因为:
https://vuejs.org/v2/guide/list.html#Caveats
由于 javascript 的限制,Vue 无法检测到数组的以下更改
问题:
我想知道如何更新数组?我还希望在离开文本框时使用@blur 事件进行更改。我想看看有什么方法可以做到这一点。
我阅读了这些材料:
https://codingexplained.com/coding/front-end/vue-js/array-change-detection https://vuejs.org/v2/guide/list.html
但我的示例似乎有点复杂,因为它具有关联的索引,并且数组具有复杂的对象。
2018 年 4 月 12 日更新
在我的 addItem() 中发现了:
item = this.conditionItems[this.conditionItems.length - 1].item);
到
item = JSON.parse(JSON.stringify(this.conditionItems[this.conditionItems.length - 1].item));
我认为下面答案中的同步修饰符会导致问题,因为它复制了所有项目。但事实并非如此。我正在复制一个 vue 对象(包括可观察的属性),这导致它发生。 JSON parse 和 JSON stringify 方法仅将属性复制为普通对象,没有可观察的属性。这是在这里讨论的:
https://github.com/vuejs/Discussion/issues/292
【问题讨论】:
【参考方案1】:问题是道具从一个方向流向一个方向,从父母到孩子。
在 child 中使用 v-model 设置值不会影响 parent 的数据。
Vue 有一个快捷方式可以更轻松地更新父级的数据。它叫做.sync modifier。
方法如下。
在 sub-comp.vue 中
<template>
<div>
<input type="text" class="form-control" :value="textA" @input="$emit('update:textA', $event.target.value)" >
<input type="text" class="form-control" :value="textB" @input="$emit('update:textB', $event.target.value)">
<input type="text" class="form-control" :value="textC" @input="$emit('update:textC', $event.target.value)">
</div>
</template>
<script>
export default
// remains the same
</script>
添加道具时添加.sync
<sub-comp
:textA.sync="listItem.item.textA" // this will have the same effect of v-on:update:textA="listItem.item.textA = $event"
:textB.sync="listItem.item.textB"
:textC.sync="listItem.item.textC"
/>
更新:
如果您有反应性问题,请不要使用 .sync,添加自定义事件并使用 $set
<sub-comp
:textA="listItem.item.textA" v-on:update:textA="$set('listItem.item','textA', $event)"
/>
【讨论】:
哇,谢谢你指点我这个。我得到了它的某些部分工作,如果我没有遇到任何问题,我将标记为已回答。以上是关于Vue JS 2 中复杂对象数组的数组更改检测的主要内容,如果未能解决你的问题,请参考以下文章