EditableProTable
EditableProTable 复用 ProTable 的列模型、编辑状态机和校验逻辑,面向“整张表就是一个表单字段”的场景。它默认关闭搜索、分页、工具选项和窗口聚焦刷新。
何时使用
- 需要在表格中连续新增、修改或删除多条记录,并把整张表作为一个受控值提交。
- 需要复用
ProTable的列配置、校验和插槽,同时默认关闭查询、分页等浏览型能力。 - 只编辑单条记录、且仍以查询浏览为主时,可以直接使用
ProTable的内建编辑能力。
示例
受控编辑、新建记录与组件实例
查看完整代码
<script setup lang="ts">
import { ref } from 'vue'
import {
EditableProTable,
type EditableConfig,
type EditableProTableInstance,
type ProColumns,
type ProKey,
type RecordCreatorProps,
} from 'antdv-next-pro'
type Member = Record<string, unknown> & {
id: number
name: string
role: '开发' | '设计' | '测试'
allocation: number
active: boolean
}
const tableRef = ref<EditableProTableInstance<Member>>()
const value = ref<Member[]>([
{ id: 1, name: '林默', role: '开发', allocation: 80, active: true },
{ id: 2, name: '周芮', role: '设计', allocation: 60, active: true },
])
const editableKeys = ref<ProKey[]>([])
const lastAction = ref('editableKeys 由 v-model 完整控制')
let sequence = 3
const columns: ProColumns<Member>[] = [
{
title: '成员',
dataIndex: 'name',
valueType: 'text',
formItemProps: { rules: [{ required: true, message: '请输入成员姓名' }] },
},
{
title: '角色',
dataIndex: 'role',
valueType: 'select',
valueEnum: { 开发: '开发', 设计: '设计', 测试: '测试' },
},
{ title: '投入比例', dataIndex: 'allocation', valueType: 'percent' },
{ title: '参与项目', dataIndex: 'active', valueType: 'switch' },
{ title: '操作', valueType: 'option', width: 160 },
]
const editable: EditableConfig<Member> = {
type: 'multiple',
async onSave(_key, record) {
await new Promise((resolve) => setTimeout(resolve, 120))
lastAction.value = `已保存「${record.name}」`
},
}
const recordCreatorProps: RecordCreatorProps<Member> = {
record: () => ({
id: sequence++,
name: '',
role: '开发',
allocation: 50,
active: true,
}),
position: 'bottom',
creatorButtonText: '添加成员',
newRecordType: 'dataSource',
}
const editFirst = () => {
const first = value.value[0]
if (first && tableRef.value?.startEditable(first.id)) {
lastAction.value = '正在编辑第一行'
}
}
const patchFirst = () => {
const first = value.value[0]
if (first && tableRef.value?.setRowData(first.id, { allocation: 100 })) {
lastAction.value = 'setRowData 已浅合并第一行'
}
}
</script>
<template>
<div class="demo-frame vp-raw">
<p class="demo-label">LIVE · CONTROLLED VALUE + COMPONENT REF</p>
<div class="demo-actions">
<span>编辑中:{{ editableKeys.length ? editableKeys.join(', ') : '无' }}</span>
<span>{{ lastAction }}</span>
<button type="button" @click="editFirst">编辑第一行</button>
<button type="button" @click="patchFirst">投入改为 100%</button>
</div>
<EditableProTable
ref="tableRef"
v-model:value="value"
v-model:editable-keys="editableKeys"
:columns="columns"
:editable="editable"
:record-creator-props="recordCreatorProps"
:max-length="5"
row-key="id"
@values-change="lastAction = `完整 value 已更新,共 ${value.length} 行`"
@editable-error="lastAction = '保存失败,编辑状态已保留'"
>
<template #header-role="{ column }"> {{ column.title }}(共享列插槽) </template>
</EditableProTable>
</div>
</template>
<style scoped>
.demo-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
margin-bottom: 14px;
color: #64748b;
font-size: 12px;
}
.demo-actions button {
padding: 5px 10px;
border: 1px solid #bfd2e7;
border-radius: 6px;
background: #fff;
color: #1768d3;
cursor: pointer;
}
</style>受控数据与编辑状态
v-model:value 是完整数据的唯一受控入口,不再提供语义冲突的 dataSource。defaultValue 可提供非受控初始值。
<EditableProTable
v-model:value="members"
v-model:editable-keys="editableKeys"
:columns="columns"
:editable="{ type: 'multiple', onSave, onDelete }"
:record-creator-props="recordCreatorProps"
row-key="id"
/>editable.type 可设为 single 或 multiple。onSave、onCancel、onDelete 支持 Promise;保存或删除返回 false 时保持当前编辑/数据状态。列级 editable 可根据记录决定是否允许编辑。
校验与生命周期
校验规则放在列的 formItemProps.rules:
const columns: ProColumns<Member>[] = [
{
title: '姓名',
dataIndex: 'name',
valueType: 'text',
formItemProps: {
rules: [{ required: true, message: '请输入姓名' }],
},
},
]
const editable: EditableConfig<Member> = {
type: 'multiple',
async onSave(key, record, origin) {
await api.save(record)
},
async onDelete(key, record) {
await api.remove(record.id)
return true
},
}校验不通过时 saveEditable 返回 false;生命周期抛错会触发 editable-error。formItemProps Prop 则用于将整个 EditableProTable 包装为一个 Antdv Next FormItem,方便嵌入外层表单。
新建记录
const recordCreatorProps: RecordCreatorProps<Member> = {
record: () => ({
id: crypto.randomUUID(),
name: '',
}),
position: 'bottom',
parentKey: undefined,
newRecordType: 'dataSource',
creatorButtonText: '添加成员',
}| 字段 | 说明 |
|---|---|
record | 记录对象或每次创建时执行的工厂函数 |
position | top / bottom,默认底部 |
parentKey | 树形数据的新记录父节点 |
newRecordType | dataSource 立即写入模型;cache 保存成功后写入 |
creatorButtonText | 创建按钮文本 |
每条新记录必须产生唯一 rowKey。maxLength 按展开后的树形记录总数计算;达到上限后隐藏创建按钮,通过 ref 调用 addEditRecord 时也会遵守该限制。
共用字段核心与 FormItem 边界
EditableProTable 不维护单独的字段映射,而是通过 ProTable 复用 ProFormFields 的裸控件核心。treeSelect、slider、segmented 可和既有 valueType 一样用于可编辑列;checked 型字段和异步选项也使用同一套 v-model、竞态与错误处理。
列级 formItemProps 只提供单元格校验和字段配置,不创建嵌套 FormItem。组件根级的 formItemProps 则只负责把整张 EditableProTable 包装为一个外层 FormItem,二者职责不会交叉。自定义编辑器仍使用列级 renderFormItem,并通过 context.update(value) 写回草稿。
API
属性
| Prop | 类型 | 说明 |
|---|---|---|
columns | ProColumns<T>[] | 与 ProTable 共用的列模型 |
value / defaultValue | T[] | 受控值与非受控初始值 |
editableKeys | ProKey[] | 当前编辑行,支持双向绑定 |
editable | false | EditableConfig<T> | 编辑模式和生命周期 |
recordCreatorProps | false | RecordCreatorProps<T> | 创建行配置 |
maxLength | number | 最大记录数 |
formItemProps | Record<string, unknown> | 外层 Antdv Next FormItem 配置 |
onValuesChange | (values, changedRecord) => void | 完整数据变化回调 |
onTableChange | (pagination, filters, sorter) => void | 表格状态回调 |
request / params / postData | 与 ProTable 相同 | 可选远程初始化/刷新 |
toolbar / rowSelection / columnsState | 与 ProTable 相同 | 可按需重新启用相关能力 |
polling / manualRequest | 与 ProTable 相同 | 远程请求控制 |
scroll / size / bordered | 与 ProTable 相同 | 表格外观 |
事件
onValuesChange / onTableChange Props 与 @values-change / @table-change 是同一条 Vue 监听通道的两种写法,请任选一种。每次变化只派发一次,不要为同一个处理函数同时写两种语法:
| 事件 | 参数 | 说明 |
|---|---|---|
update:value | rows | v-model:value 更新 |
update:editable-keys | keys | v-model:editable-keys 更新 |
values-change | rows, changedRecord | 任一记录变化 |
table-change | pagination, filters, sorter | 表格状态变化 |
request-error | error | 远程请求失败 |
editable-error | error | 编辑生命周期失败 |
插槽
EditableProTable 会将插槽全部转发给内部 ProTable,因此可以使用:
toolbar-title、toolbar-actions。header-${columnKey}。cell-${columnKey}或${columnKey},参数为{ value, record, index, column, editable }。- 底层 Antdv Next Table 的其他插槽。
组件实例
EditableProTableInstance<T> 包含 ProTable 的全部实例方法,并额外提供整表读写:
const editableRef = ref<EditableProTableInstance<Member>>()
editableRef.value?.startEditable(memberId)
const first = editableRef.value?.getRowData(0)
const all = editableRef.value?.getRowsData()
editableRef.value?.setRowData(memberId, { allocation: 100 })| 方法 | 说明 |
|---|---|
getRowData(indexOrKey) | 数字先按精确 rowKey 查找,再回退为顶层索引 |
getRowsData() | 读取当前完整数据副本 |
setRowData(indexOrKey, value) | 按同样的 key/索引规则查找,浅合并后更新 v-model:value |
继承的方法包括 reload、reset、setPageInfo、clearSelected、fullScreen、scrollTo、startEditable、saveEditable、cancelEditable 与 addEditRecord。