需求与限制
vxe-table 内置的行编辑功能默认是单行编辑,同一时间只能激活一行。虽然它提供了 editConfig、editRules、CRUD 相关方法,但如果业务要求"同时编辑多行",就需要自己维护编辑状态。
- 自定义多行编辑的核心思路很简单:
- 给每一行数据增加一个 isEdit 标记;
- 在列插槽中根据 row.isEdit 切换编辑组件和普通文本;
- 编辑前备份原始数据,取消时还原;
- 保存时调用接口,成功后关闭编辑态;
- 可以额外实现"保存全部""取消全部"。
需要注意:一旦采用自定义多行编辑,就无法直接使用 vxe-table 内置的 CRUD 方法、editRules 数据校验等功能,这些都需要自行实现。
代码

html
<template>
<div>
<vxe-grid v-bind="gridOptions">
<template #name_default="{ row }">
<vxe-input v-if="row.isEdit" v-model="row.name"></vxe-input>
<span v-else>{{ row.name }}</span>
</template>
<template #sex_default="{ row }">
<vxe-select v-if="row.isEdit" v-model="row.sex" :options="sexList"></vxe-select>
<span v-else>{{ row.sex }}</span>
</template>
<template #age_default="{ row }">
<vxe-input v-if="row.isEdit" v-model="row.age"></vxe-input>
<span v-else>{{ row.age }}</span>
</template>
<template #action="{ row }">
<vxe-button v-if="row.isEdit" mode="text" status="success" :loading="row.isLoading" @click="handleSave(row)">保存</vxe-button>
<vxe-button v-else mode="text" status="primary" @click="handleEdit(row)">编辑</vxe-button>
<vxe-button v-if="row.isEdit" mode="text" @click="cancelEdit(row)">取消</vxe-button>
</template>
</vxe-grid>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
const sexList = ref([
{ label: '男', value: 'Man' },
{ label: '女', value: 'Women' }
])
const gridOptions = reactive({
border: true,
showOverflow: true,
rowConfig: {
keyField: 'id'
},
columns: [
{ type: 'seq', width: 70 },
{ field: 'name', title: 'Name', slots: { default: 'name_default' } },
{ field: 'sex', title: 'Sex', slots: { default: 'sex_default' } },
{ field: 'age', title: 'Age', slots: { default: 'age_default' } },
{ field: 'action', title: '操作', width: 140, slots: { default: 'action' } }
],
data: [
{ id: 10001, name: 'Test1', role: 'Develop', sex: 'Man', age: 28, address: 'test abc', isEdit: false, isLoading: false },
{ id: 10002, name: 'Test2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou', isEdit: false, isLoading: false },
{ id: 10003, name: 'Test3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai', isEdit: false, isLoading: false },
{ id: 10004, name: 'Test4', role: 'Designer', sex: 'Women', age: 24, address: 'Shanghai', isEdit: false, isLoading: false }
]
})
const handleEdit = (row) => {
row.isEdit = true
}
const cancelEdit = (row) => {
row.isEdit = false
}
const handleSave = (row) => {
row.isLoading = true
// 模拟后端接口
setTimeout(() => {
row.isEdit = false
row.isLoading = false
}, 300)
}
</script>
核心实现解析
1. 通过自定义插槽切换编辑态
每一列都使用 vxe-table 的插槽,根据 row.isEdit 决定显示输入组件还是普通文本:
html
<template #name_default="{ row }">
<vxe-input v-if="row.isEdit" v-model="row.name" />
<span v-else>{{ row.name }}</span>
</template>
因为 isEdit 是挂在每一行上的,所以可以同时把多行设置为 isEdit: true,从而实现多行同时编辑。
2. 编辑前备份,取消时还原
如果直接修改 row.name,点击取消时数据已经被改掉了。因此在进入编辑态时先保存一份快照:
js
const handleEdit = (row) => {
if (!row._originalData) {
row._originalData = {
name: row.name,
sex: row.sex,
age: row.age
}
}
row.isEdit = true
}
取消时再还原:
js
Object.assign(row, row._originalData)
delete row._originalData
row.isEdit = false
3.保存时过滤前端状态字段
isEdit、isLoading、_originalData、_isNew 都是前端状态,不应该提交给后端:
js
const getSubmitData = (row) => {
const data = { ...row }
delete data.isEdit
delete data.isLoading
delete data._originalData
delete data._isNew
return data
}
4. 自行校验数据
由于不能使用内置 editRules,这里在保存前手动校验:
js
const validateRow = (row) => {
if (!row.name) {
alert('姓名不能为空')
return false
}
if (row.age === '' || row.age === null || row.age === undefined) {
alert('年龄不能为空')
return false
}
return true
}
实际项目中可以替换成 VxeUI.modal.message 或自己的表单校验逻辑
5. 批量保存与批量取消
保存全部时,找出所有处于编辑态的行,统一调用保存方法:
js
const saveAll = async () => {
const editRows = gridOptions.data.filter((row) => row.isEdit)
if (!editRows.length) return
savingAll.value = true
try {
await Promise.all(editRows.map((row) => handleSave(row)))
} finally {
savingAll.value = false
}
}
取消全部时注意复制数组,避免取消新增行时删除数组导致遍历异常:
js
;[...gridOptions.data].forEach((row) => {
if (row.isEdit) {
cancelEdit(row)
}
})
注意事项与局限
- 不能使用内置 CRUD 和校验
- 自定义多行编辑后,vxe-table 内置的 insert、remove、editRules 等能力无法直接配合使用,需要自己维护。
- 行数据必须有唯一 key
- 建议配置 rowConfig.keyField: 'id',并保证每行 id 唯一。
- 提交前剔除前端状态字段
- isEdit、isLoading、_originalData、_isNew 只用于前端交互,提交接口前要删除。
- 保存失败时保持编辑态
- 示例中保存失败后不会关闭编辑态,方便用户重试。实际项目可以根据需求处理。
- 新增行取消应删除
- 示例通过 _isNew 标记新增行,取消时直接从表格数据中移除。
- 数据量大时建议优化编辑状态管理
- 当前方案把编辑状态直接挂在行数据上,简单直观,适合中小数据量。如果数据量很大,可以用 Set 单独存储正在编辑的行 id,减少对原始数据的污染。
通过给每行数据增加 isEdit 标记,再配合 vxe-table 的列插槽,就可以实现自定义多行编辑。虽然失去了一部分内置能力,但换来更高的灵活性,适合需要同时编辑多行、批量保存、自定义交互的表格场景。
如果项目对数据校验和 CRUD 依赖较重,也可以考虑继续使用 vxe-table 内置的单行编辑;如果必须多行编辑,则可以使用本文方案自行封装编辑状态、校验和保存逻辑。