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 中复杂对象数组的数组更改检测的主要内容,如果未能解决你的问题,请参考以下文章

Vue.js v-for 循环绑定数组中的项目对象并在更改时更新

使用 Vue.JS 编辑数组的对象

js中数组操作

vue 数组和对象渲染问题

在 vue.js 中更改复杂的计算对象

Vue.js 如何在 v-model 输入的数组中定位具有未知名称的对象