Grid 配置式表格编辑功能问题

105 阅读3分钟

🧩 Grid 配置式表格编辑功能问题

🔍 需求描述

点击"编辑"按钮后,对应行内的单元格转变为输入框以供修改,点击"保存"时将新数据提交至后端进行更新。

🔥 遇到的问题

在编辑功能中,点击某行的"编辑"按钮后:

  • 该行单元格转为输入框,可进行修改
  • "编辑"按钮切换为"保存"和"取消"按钮
  • 点击"保存"时,通过 row参数将整行数据发送至后端

问题现象

saveForm方法中,console.log(row)显示的是修改后的新值

但实际网络请求的 payload 中,row对象包含的却是修改前的原始数据

导致前后端数据不一致


💻 代码配置

Grid 配置项

export const formOptions = reactive({
  items: [
    {
      span: 24,
      children: [
        {
          field: "value1",
          title: "值1",
          span: 10,
          slots: { default: "type" },
        },
      ],
    },
    {
      span: 24,
      children: [
        {
          field: "value2",
          title: "值2",
          span: 10,
          itemRender: {
            name: "VxeSelect",
            props: {
              placeholder: "请选择类型",
              options: [
                { label: "全部", value: "all" },
                { label: "w", value: "w" },
                { label: "e", value: "e" },
                { label: "r", value: "r" },
                { label: "t", value: "t" },
                { label: "y", value: "y" },
              ],
            },
          },
        },
        {
          align: "left",
          span: 3,
          slots: { default: "butttons" },
        },
      ],
    },
  ],
});
​
// 表格配置 - 使用计算属性确保响应式更新
export const gridOptions = reactive({
  ...gridConfig,
  keepSource: true, // 🔑 关键配置
  columns: [
    {
      field: "code",
      title: "编号",
      maxWidth: 200,
      sortable: true,
    },
    {
      field: "type",
      title: "类型",
      sortable: true,
    },
    {
      field: "streetNo",
      title: "街道号",
      sortable: true,
    },
    {
      field: "operation",
      title: "操作",
      width: 200,
      fixed: "right",
      slots: { default: "buttons" }, // 🔑 操作按钮插槽
    },
  ],
});

Vue 文件

<template>
  <vxe-grid
    v-bind="gridOptPage"
    :data="gridData"
    ref="tableRef"
    :edit-config="editConfig"
  >
    <!-- 操作按钮模板 -->
    <template #buttons="{ row }">
      <template v-if="hasEditStatus(row)">
        <vxe-button @click="saveRowEvent(row)" status="primary">保存</vxe-button>
        <vxe-button @click="cancelRowEvent(row)">取消</vxe-button>
      </template>
      <template v-else>
        <vxe-button @click="editRowEvent(row)" status="primary">编辑</vxe-button>
      </template>
    </template>
  </vxe-grid>
</template><script setup name="configuration">
import { ref, reactive } from "vue";
import { formOptions, gridOptions } from "./utils/configurationGrid";
import { VxeUI } from "vxe-table";
​
// 保存方法
const saveRowEvent = async (row) => {
  const $table = tableRef.value;
  if (!$table) return;
​
  try {
    await updateConfigurationApi(row); // ⚠️ 这里发送的是原始数据
    await $table.clearEdit(); // ✅ 清除编辑状态
    VxeUI.modal.message({
      content: `保存成功!`,
      status: "success",
    });
  } catch (error) {
    console.error("保存失败:", error);
    VxeUI.modal.message({
      content: `保存失败: ${error.message}`,
      status: "error",
    });
  }
};
</script>

🔍 问题排查与解决

💡 思路一:编辑触发方式

edit-config中,trigger有三种模式:

  • manual(手动触发,仅适用于 mode=row)✅ 正确选择
  • click(点击触发)
  • dblclick(双击触发)

由于是通过点击"编辑"按钮触发,使用 manual模式是正确的,初步排除触发方式的问题。

💡 思路二:深浅拷贝问题

怀疑是 row对象为浅拷贝,尝试使用深拷贝方案:

const newRow = JSON.parse(JSON.stringify(row))

但打印结果一致,排除该问题 ❌

💡 思路三:数据同步机制

关键发现:vxetable 编辑时存在两种数据状态:

  • 编辑前的原始数据(默认使用)
  • 编辑后的新数据(实际需要)

每次传递的都是编辑前的数据,导致请求载荷始终为旧值 ❌


🚀 解决方案

方案一:获取更新记录集(推荐)

通过 getRecordset()方法获取状态变化的记录,从中提取已更新的数据:

const saveRowEvent = async (row) => {
  const $table = tableRef.value;
  if (!$table) return;
​
  try {
    // 🚨 关键修复 - 获取所有更新记录
    const recordset = $table.getRecordset();
    
    // 🔍 从更新记录中查找当前行
    const updatedRow = recordset.updateRecords.find(
      (item) => item.id === row.id // 根据实际ID字段调整
    );
    
    // ✅ 使用更新后的数据或原始数据作为后备
    const dataToSave = updatedRow || row;
    
    // ✨ 发送更新后的数据
    await updateConfigurationApi(dataToSave);
    
    await $table.clearEdit();
    VxeUI.modal.message({ content: "保存成功!", status: "success" });
  } catch (error) {
    console.error("保存失败:", error);
    VxeUI.modal.message({ 
      content: `保存失败: ${error.message}`, 
      status: "error" 
    });
  }
};

方案二:启用实时同步(简单高效)

在列配置中设置 immediate: true,实现输入值实时同步:

{
  field: "value1",
  title: "值1",
  sortable: true,
  editRender: { 
    name: "VxeInput", 
    immediate: true //  启用实时同步
  },
}

🧠 总结与最佳实践

解决方案适用场景优点注意事项
getRecordset()方法需要精确控制数据提交的场景灵活性强,可批量处理需要手动匹配行记录
immediate: true配置大多数编辑同步需求配置简单,自动同步切换模块时需注意数据重置

💎 核心要点

  1. 数据状态是关键:vxetable 默认使用编辑前的原始数据
  2. keepSource: true:确保表格维护原始数据副本
  3. 实时更新配置immediate: true是最高效的解决方案
  4. 记录集操作getRecordset()提供了更精细的控制能力

📌 重要提示:使用 immediate时,若切换模块后重新请求数据,需注意数据状态可能被重置,类似 watch监听机制。

🎯 最终结果

通过以上两种方案,成功解决了编辑后数据同步问题,现在:

  • 前端显示值 ✅

  • console.log输出值 ✅

  • 请求载荷值 ✅

    三者完美一致!