You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vuetify CRUD表格编辑对话框异常:修改本地对象同步更新表格

Vuetify CRUD表格编辑对话框同步修改原数据问题解决

我基于Vuetify开发一个数据操作的简易CRUD表格,已用模拟数据复现问题,目前实现了FoodTable、EditDialog和Delete三个组件。遇到的异常:尝试传递对象副本给EditDialog组件,但修改对话框中的值时,DataTable里的对应值也会同步更新。

相关代码

FoodTable.vue

<template>
    <div>
        <EditDialog :IsOpen="editIsOpen" :EditObject="editObject" @edit-closed="editClosed" />
        <v-data-table :headers="headers" :items="items">
            <template v-slot:item.actions="{ item }">
                <v-icon>mdi-delete</v-icon>
                <v-icon @click="openEdit(item)">mdi-pencil</v-icon>
            </template>
        </v-data-table>
    </div>
</template>

<script>
import EditDialog from '../components/EditDialog.vue';
export default {
    name: 'FoodTable',
    components: {
        EditDialog,
    },
    data() {
        return {
            headers: [
                {
                    text: 'Dessert (100g serving)',
                    align: 'start',
                    sortable: false,
                    value: 'name',
                },
                { text: 'Calories', value: 'calories' },
                { text: 'Fat (g)', value: 'fat' },
                { text: 'Carbs (g)', value: 'carbs' },
                { text: 'Protein (g)', value: 'protein' },
                { text: 'Actions', value: 'actions', sortable: false },
            ],
            items: [
                {
                    name: 'Frozen Yogurt',
                    calories: 159,
                    fat: 6.0,
                    carbs: 24,
                    protein: 4.0,
                },
                {
                    name: 'Ice cream sandwich',
                    calories: 237,
                    fat: 9.0,
                    carbs: 37,
                    protein: 4.3,
                },
            ],
            // edit
            editIsOpen: false,
            editObject: {},
            // delete
        }
    },
    methods: {
        openEdit(item) {
            this.editIsOpen = true;
            this.editObject = item;
        },
        editClosed() {
            this.editIsOpen = false;
            this.editObject = {};
        }
    }
}
</script>

EditDialog.vue

<template>
    <v-dialog v-model="isOpen" persistent>
        <v-card>
            <v-card-title>Edit</v-card-title>
            <v-card-text>
                <v-text-field v-model="editObject.calories"></v-text-field>
            </v-card-text>
            <v-card-actions>
                <v-spacer></v-spacer>
                <v-btn @click="cancelEdit">Cancel</v-btn>
                <v-btn @click="confirmEdit">Confirm</v-btn>
            </v-card-actions>
        </v-card>
    </v-dialog>
</template>

<script>
export default {
    name: 'EditDialog',
    props: {
        IsOpen: Boolean,
        EditObject: Object,
    },
    data() {
        return {
            isOpen: this.IsOpen,
            editObject: this.EditObject,
        }
    },
    methods: {
        cancelEdit() {
            this.$emit('edit-closed');
        },
        confirmEdit() {
            this.$emit('edit-closed');
        }
    },
    watch: {
        IsOpen() {
            this.isOpen = this.IsOpen;
        },
        EditObject(newEditObject){
            this.editObject = newEditObject;
        }
    }
}
</script>

期望流程

  • 点击编辑图标触发@click事件,调用openEdit方法并传入当前item;
  • 设置editIsOpen为true,并将editObject赋值为传入的item;
  • 将这些值作为props传递给EditDialog组件;
  • EditDialog组件监听props变化,将本地变量isOpen和editObject设置为props的值;
  • EditDialog中的文本框绑定本地editObject的属性,仅修改本地对象;
  • 点击提交后,组件向上传递新对象并更新表格数据(暂未实现)。

问题点

修改对话框中的值时,不仅本地editObject被修改,表格中对应的变量也被同步修改。

原因分析

JavaScript中对象是按引用传递的:

  1. 父组件openEdit方法里this.editObject = item只是把item的引用赋值给了editObject;
  2. 子组件把props的EditObject赋值给本地editObject时,同样是传递引用;
  3. 所以修改子组件中editObject的属性,本质上是直接修改原数组items中对应对象的属性,导致表格数据同步变化。

解决方法

在子组件接收EditObject时,创建对象的副本(断开引用),可以通过手动复制属性、Object.assign或者扩展运算符...实现。这里修改EditDialog的watch逻辑:

watch: {
    IsOpen() {
        this.isOpen = this.IsOpen;
        // 创建对象副本,断开与原对象的引用
        let editObject = {
            name: this.EditObject.name,
            calories: this.EditObject.calories,
            fat: this.EditObject.fat,
            carbs: this.EditObject.carbs,
            protein: this.EditObject.protein,
        }
        this.editObject = editObject;
    },
    // 也可以优化EditObject的watch,直接创建副本
    EditObject(newEditObject){
        this.editObject = {...newEditObject}; // 扩展运算符更简洁
    }
}

这样修改对话框中的值时,只会修改本地副本,不会影响原表格数据,点击确认后再将副本数据传递给父组件更新原数组即可。

内容的提问来源于stack exchange,提问作者sdman02

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 13:37:01