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

Vue 3编辑模态框数据流异常:二次打开编辑无响应问题求解

问题根因

你的代码逻辑存在两个核心问题,导致编辑功能仅首次生效:

  • 本地表单数据仅初始化一次。EditModal.vue中写在<script setup>顶层的const data = Object.assign({}, toRaw(props.data))逻辑,只会在组件首次挂载时执行一次,后续props.data发生变化时,组件内部拷贝的本地表单数据不会同步更新。
  • 保存后未重置模态框状态。你在updateItem方法执行完列表更新后,没有把state.showModal设为false,也没有清空state.currentItem,导致第二次点击其他项的编辑按钮时,v-if="state.currentItem"的判定结果始终为真,EditModal组件不会被销毁重建,初始化拷贝逻辑自然不会重新触发,表单会一直保留第一次编辑的旧数据,看起来就像点击没有反应。

另外你的列表v-for没有绑定key,会增加Vue列表节点复用时的异常概率,属于不规范写法。
你一开始为了避免直接修改原始数据做prop拷贝的思路是完全正确的,问题出在拷贝逻辑的执行时机和状态重置缺失上。

修复方案

1. 修复App.vue状态逻辑

首先补全保存后的状态重置,同时给v-for加上唯一key:

<script setup>
  import { reactive } from 'vue';
  import EditModal from './components/EditModal.vue'
  import ListItem from './components/ListItem.vue'

  const state = reactive({
    items: [
      { id: 1, title: 'Item 1' },
      { id: 2, title: 'Item 2' }
    ],
    currentItem: null,
    showModal: false
  });

  function editItem(itemData) {
    state.showModal = true;
    state.currentItem = itemData;
  }

  function updateItem(itemData) {
    state.items = state.items.map(item => item.id === itemData.id ? itemData : item);
    // 保存后关闭模态框、清空当前选中项
    state.showModal = false;
    state.currentItem = null;
  }
</script>

<template>
  <div>
    <EditModal
      v-if="state.currentItem"
      :show="state.showModal"
      :data="state.currentItem"
      @save="itemData => updateItem(itemData)"
    />

    <ListItem
      v-for="itemData in state.items"
      :key="itemData.id"
      :data="itemData"
      @edit="itemData => editItem(itemData)"
    />
  </div>
</template>

2. 优化EditModal.vue的数据同步逻辑

为了避免后续状态调整(比如加取消按钮、模态框做缓存不销毁)时再次出现数据不同步问题,增加对props.data的监听,每次传入新的编辑项时自动同步更新本地表单副本,同时补全emits声明:

<script setup>
  import { reactive, toRaw, watch } from 'vue';

  const props = defineProps(['show', 'data']);
  const emit = defineEmits(['save']);

  // 封装表单初始化方法,支持重复调用
  const initForm = () => {
    // 当前场景是单层数据,浅拷贝即可;如果有嵌套对象,请改用深拷贝:
    // 方式1:structuredClone(toRaw(props.data)) (现代浏览器原生支持)
    // 方式2:JSON.parse(JSON.stringify(toRaw(props.data))) (兼容旧环境)
    return reactive(Object.assign({}, toRaw(props.data)));
  }
  const formData = initForm();

  // 监听传入的编辑项变化,同步更新本地表单数据
  watch(() => props.data, (newVal) => {
    if (!newVal) return;
    Object.assign(formData, toRaw(newVal));
  }, { immediate: true })
</script>

<template>
  <div v-show="show">
    <div class="modal">
      <div class="modal-inner">
        <input v-model="formData.title">
        <button @click="emit('save', formData)">Save</button>
      </div>
    </div>
  </div>
</template>

ListItem.vue逻辑本身没有问题,不需要修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 16:06:30