🧩 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配置 | 大多数编辑同步需求 | 配置简单,自动同步 | 切换模块时需注意数据重置 |
💎 核心要点
- 数据状态是关键:vxetable 默认使用编辑前的原始数据
keepSource: true:确保表格维护原始数据副本- 实时更新配置:
immediate: true是最高效的解决方案 - 记录集操作:
getRecordset()提供了更精细的控制能力
📌 重要提示:使用
immediate时,若切换模块后重新请求数据,需注意数据状态可能被重置,类似watch监听机制。
🎯 最终结果
通过以上两种方案,成功解决了编辑后数据同步问题,现在:
-
前端显示值 ✅
-
console.log输出值 ✅ -
请求载荷值 ✅
三者完美一致!