Skip to content

Commit

Permalink
[Table]支持行编辑功能 (#1186)
Browse files Browse the repository at this point in the history
* fix(table): editable-cell: abortEditOnEvent can not trigger onEdited

* feat(table): editable-row

* feat(table): support validate for row edit

* feat(table): show error list for eidt row
  • Loading branch information
chaishi authored Jul 11, 2022
1 parent 1a1b6bd commit 3bb0731
Show file tree
Hide file tree
Showing 12 changed files with 1,190 additions and 96 deletions.
21 changes: 7 additions & 14 deletions examples/table/demos/editable-cell.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div>
<!-- 当前示例包含:输入框、单选、多选、日期 等场景 -->
<t-table row-key="key" :columns="columns" :data="data" bordered />
<t-table row-key="key" :columns="columns" :data="data" bordered @row-validate="onRowValidate" />
</div>
</template>

Expand All @@ -27,6 +27,10 @@ const initData = new Array(5).fill(null).map((_, i) => ({
const align = ref('left');
const data = ref([...initData]);
const onRowValidate = (params) => {
console.log('validate:', params);
};
const columns = computed(() => [
{
title: 'FirstName',
Expand Down Expand Up @@ -118,12 +122,10 @@ const columns = computed(() => [
{
title: 'Date',
colKey: 'createTime',
// props, 透传全部属性到 DatePicker 组件
edit: {
component: DatePicker,
props: {
mode: 'date',
},
// props, 透传全部属性到 DatePicker 组件
props: {},
// 除了点击非自身元素退出编辑态之外,还有哪些事件退出编辑态
abortEditOnEvent: ['onChange'],
onEdited: (context) => {
Expand All @@ -135,12 +137,3 @@ const columns = computed(() => [
},
]);
</script>
<style scoped>
.table-operations {
margin-bottom: 16px;
}
.table-operations > button {
margin-right: 8px;
}
</style>
219 changes: 219 additions & 0 deletions examples/table/demos/editable-row.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
<template>
<div class="t-table-demo__editable-row">
<!-- 当前示例包含:输入框、单选、多选、日期 等场景 -->
<t-table
ref="tableRef"
row-key="key"
:columns="columns"
:data="data"
:editable-row-keys="editableRowKeys"
vertical-align="top"
bordered
@row-edit="onRowEdit"
@row-validate="onRowValidate"
/>
</div>
</template>

<script setup lang="jsx">
import { ref, computed } from 'vue';
import { Input, Select, DatePicker, MessagePlugin, Button } from 'tdesign-vue-next';
const initData = new Array(5).fill(null).map((_, i) => ({
key: String(i + 1),
firstName: ['Eric', 'Gilberta', 'Heriberto', 'Lazarus', 'Zandra'][i % 4],
framework: ['Vue', 'React', 'Miniprogram', 'Flutter'][i % 4],
email: [
'espinke0@apache.org',
'gpurves1@issuu.com',
'hkment2@nsw.gov.au',
'lskures3@apache.org',
'zcroson5@virginia.edu',
][i % 4],
letters: [['A'], ['B', 'E'], ['C'], ['D', 'G', 'H']][i % 4],
createTime: ['2021-11-01', '2021-12-01', '2022-01-01', '2022-02-01', '2022-03-01'][i % 4],
}));
const tableRef = ref();
const align = ref('left');
const data = ref([...initData]);
const editableRowKeys = ref(['1']);
const currentSaveId = ref('');
// 保存变化过的行信息
const editMap = {};
const onEdit = (e) => {
const { id } = e.currentTarget.dataset;
if (!editableRowKeys.value.includes(id)) {
editableRowKeys.value.push(id);
}
};
// 更新 editableRowKeys
const updateEditState = (id) => {
const index = editableRowKeys.value.findIndex((t) => t === id);
editableRowKeys.value.splice(index, 1);
};
const onCancel = (e) => {
const { id } = e.currentTarget.dataset;
updateEditState(id);
};
const onSave = (e) => {
const { id } = e.currentTarget.dataset;
currentSaveId.value = id;
// 触发内部校验,而后在 onRowValidate 中接收异步校验结果
tableRef.value.validateRowDate(id);
};
const onRowValidate = (params) => {
console.log('validate:', params);
if (params.result.length) {
const r = params.result[0];
MessagePlugin.error(`${r.col.title} ${r.errorList[0].message}`);
return;
}
// 如果是 table 的父组件主动触发校验
if (params.trigger === 'parent' && !params.result.length) {
const current = editMap[currentSaveId.value];
if (!current) return;
data.value.splice(current.rowIndex, 1, current.editedRow);
MessagePlugin.success('保存成功');
updateEditState(currentSaveId.value);
}
};
const onRowEdit = (params) => {
const { row, rowIndex, col, value } = params;
const oldRowData = editMap[row.key]?.editedRow || row;
editMap[row.key] = {
...params,
editedRow: { ...oldRowData, [col.colKey]: value },
};
};
const columns = computed(() => [
{
title: 'FirstName',
colKey: 'firstName',
align: align.value,
// 编辑状态相关配置,全部集中在 edit
edit: {
// 1. 支持任意组件。需保证组件包含 `value` 和 `onChange` 两个属性,且 onChange 的第一个参数值为 new value。
// 2. 如果希望支持校验,组件还需包含 `status` 和 `tips` 属性。具体 API 含义参考 Input 组件
component: Input,
// props, 透传全部属性到 Input 组件
props: {
clearable: true,
autofocus: true,
autoWidth: true,
},
// 校验规则,此处同 Form 表单
rules: [
{ required: true, message: '不能为空' },
{ max: 10, message: '字符数量不能超过 10', type: 'warning' },
],
showEditIcon: false,
},
},
{
title: 'Framework',
colKey: 'framework',
edit: {
component: Select,
// props, 透传全部属性到 Select 组件
props: {
autoWidth: true,
options: [
{ label: 'Vue', value: 'Vue' },
{ label: 'React', value: 'React' },
{ label: 'Miniprogram', value: 'Miniprogram' },
{ label: 'Flutter', value: 'Flutter' },
],
},
showEditIcon: false,
},
},
{
title: 'Letters',
colKey: 'letters',
cell: (h, { row }) => row.letters.join('、'),
edit: {
component: Select,
// props, 透传全部属性到 Select 组件
// props 为函数时,参数有:col, row, rowIndex, colIndex, editedRow。一般用于实现编辑组件之间的联动
props: ({ col, row, rowIndex, colIndex, editedRow }) => {
console.log(col, row, rowIndex, colIndex, editedRow);
return {
multiple: true,
minCollapsedNum: 1,
autoWidth: true,
options: [
{ label: 'A', value: 'A' },
{ label: 'B', value: 'B' },
{ label: 'C', value: 'C' },
{ label: 'D', value: 'D' },
{ label: 'E', value: 'E' },
// 如果框架选择了 React,则 Letters 隐藏 G 和 H
{ label: 'G', value: 'G', show: () => editedRow.framework !== 'React' },
{ label: 'H', value: 'H', show: () => editedRow.framework !== 'React' },
].filter((t) => (t.show === undefined ? true : t.show())),
};
},
showEditIcon: false,
},
},
{
title: 'Date',
colKey: 'createTime',
className: 't-demo-col__datepicker',
// props, 透传全部属性到 DatePicker 组件
edit: {
component: DatePicker,
showEditIcon: false,
},
},
{
title: 'Operate',
colKey: 'operate',
width: 150,
cell: (h, { row }) => {
const editable = editableRowKeys.value.includes(row.key);
return (
<div class="table-operations">
{!editable && (
<Button theme="primary" variant="text" data-id={row.key} onClick={onEdit}>
编辑
</Button>
)}
{editable && (
<Button theme="primary" variant="text" data-id={row.key} onClick={onSave}>
保存
</Button>
)}
{editable && (
<Button theme="primary" variant="text" data-id={row.key} onClick={onCancel}>
取消
</Button>
)}
</div>
);
},
},
]);
</script>

<style lang="less">
.t-table-demo__editable-row {
.table-operations > button {
padding: 0 8px;
line-height: 22px;
height: 22px;
}
.t-demo-col__datepicker .t-date-picker {
width: 120px;
}
}
</style>
14 changes: 10 additions & 4 deletions examples/table/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,10 @@ displayColumns | Array | - | 列配置功能中,当前显示的列。支持语
defaultDisplayColumns | Array | - | 列配置功能中,当前显示的列。非受控属性。TS 类型:`CheckboxGroupValue` | N
dragSort | String | - | 拖拽排序方式,值为 `row` 表示行拖拽排序,这种方式无法进行文本复制,慎用。值为`row-handler` 表示通过专门的 拖拽手柄 进行 行拖拽排序。值为 `col` 表示列顺序拖拽。`drag-col` 已废弃,请勿使用。可选项:row/row-handler/col/drag-col | N
dragSortOptions | Object | - | 拖拽排序扩展参数,具体参数见 [Sortable](https://github.com/SortableJS/Sortable)。TS 类型:`SortableOptions` | N
editableRowKeys | Array | - | 处于编辑状态的行。TS 类型:`Array<string | number>` | N
expandedRow | String / Slot / Function | - | 展开行内容,泛型 T 指表格数据类型。TS 类型:`TNode<TableExpandedRowParams<T>>` `interface TableExpandedRowParams<T> { row: T; index: number; columns: PrimaryTableCol<T>[] | BaseTableCol<T>[] }`[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts)[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N
expandedRowKeys | Array | - | 展开行。支持语法糖 `v-model:expandedRowKeys`。TS 类型:`Array<string | number>` | N
defaultExpandedRowKeys | Array | - | 展开行。非受控属性。TS 类型:`Array<string | number>` | N
expandedRowKeys | Array | [] | 展开行。支持语法糖 `v-model:expandedRowKeys`。TS 类型:`Array<string | number>` | N
defaultExpandedRowKeys | Array | [] | 展开行。非受控属性。TS 类型:`Array<string | number>` | N
expandIcon | Boolean / Slot / Function | true | 用于控制是否显示「展开图标列」,值为 `false` 则不会显示。可以精确到某一行是否显示,还可以自定义展开图标内容。`expandedRow` 存在时,该参数有效。支持全局配置 `GlobalConfigProvider`。TS 类型:`boolean | TNode<ExpandArrowRenderParams<T>>` `interface ExpandArrowRenderParams<T> { row: T; index: number }`[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts)[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N
expandOnRowClick | Boolean | - | 是否允许点击行展开 | N
filterIcon | Slot / Function | - | 自定义过滤图标,支持全局配置 `GlobalConfigProvider`。TS 类型:`TNode`[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N
Expand All @@ -114,8 +115,8 @@ defaultFilterValue | Object | - | 过滤数据的值。非受控属性。TS 类
hideSortTips | Boolean | - | 隐藏排序文本提示,支持全局配置 `GlobalConfigProvider`,默认全局配置值为 `false` | N
indeterminateSelectedRowKeys | Array | - | 半选状态行。选中行请更为使用 `selectedRowKeys` 控制。TS 类型:`Array<string | number>` | N
multipleSort | Boolean | false | 是否支持多列排序 | N
selectedRowKeys | Array | - | 选中的行,控制属性。半选状态行请更为使用 `indeterminateSelectedRowKeys` 控制。支持语法糖 `v-model:selectedRowKeys`。TS 类型:`Array<string | number>` | N
defaultSelectedRowKeys | Array | - | 选中的行,控制属性。半选状态行请更为使用 `indeterminateSelectedRowKeys` 控制。非受控属性。TS 类型:`Array<string | number>` | N
selectedRowKeys | Array | [] | 选中行,控制属性。半选状态行请更为使用 `indeterminateSelectedRowKeys` 控制。支持语法糖 `v-model:selectedRowKeys`。TS 类型:`Array<string | number>` | N
defaultSelectedRowKeys | Array | [] | 选中行,控制属性。半选状态行请更为使用 `indeterminateSelectedRowKeys` 控制。非受控属性。TS 类型:`Array<string | number>` | N
sort | Object / Array | - | 排序控制。sortBy 排序字段;descending 是否进行降序排列。值为数组时,表示正进行多字段排序。支持语法糖 `v-model:sort`。TS 类型:`TableSort` `type TableSort = SortInfo | Array<SortInfo>` `interface SortInfo { sortBy: string; descending: boolean }`[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N
defaultSort | Object / Array | - | 排序控制。sortBy 排序字段;descending 是否进行降序排列。值为数组时,表示正进行多字段排序。非受控属性。TS 类型:`TableSort` `type TableSort = SortInfo | Array<SortInfo>` `interface SortInfo { sortBy: string; descending: boolean }`[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N
sortIcon | Slot / Function | - | 自定义排序图标,支持全局配置 `GlobalConfigProvider`。TS 类型:`TNode`[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N
Expand All @@ -131,6 +132,8 @@ onDisplayColumnsChange | Function | | TS 类型:`(value: CheckboxGroupValue)
onDragSort | Function | | TS 类型:`(context: DragSortContext<T>) => void`<br/>拖拽排序时触发,`data` 表示排序前的数据,`newData` 表示拖拽排序结束后的新数据,`sort=row` 表示行拖拽事件触发,`sort=col` 表示列拖拽事件触发。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts)。<br/>`interface DragSortContext<T> { currentIndex: number; current: T; targetIndex: number; target: T; data: T[]; newData: T[]; currentData?: T[]; e: SortableEvent; sort: 'row' | 'col' }`<br/><br/>`import { SortableEvent, SortableOptions } from 'sortablejs'`<br/> | N
onExpandChange | Function | | TS 类型:`(expandedRowKeys: Array<string | number>, options: ExpandOptions<T>) => void`<br/>展开行发生变化时触发,泛型 T 指表格数据类型。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts)。<br/>`interface ExpandOptions<T> { expandedRowData: Array<T> }`<br/> | N
onFilterChange | Function | | TS 类型:`(filterValue: FilterValue, context: { col?: PrimaryTableCol<T> }) => void`<br/>过滤参数发生变化时触发,泛型 T 指表格数据类型 | N
onRowEdit | Function | | TS 类型:`(context: PrimaryTableRowEditContext<T>) => void`<br/>行编辑时触发。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts)。<br/>`type PrimaryTableRowEditContext<T> = PrimaryTableCellParams<T> & { value: any }`<br/> | N
onRowValidate | Function | | TS 类型:`(context: PrimaryTableRowValidateContext<T>) => void`<br/>行编辑校验完成后出发。`result` 表示校验结果,`trigger=self` 表示编辑组件内部触发的校验,`trigger='parent'` 表示表格父组件触发的校验。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts)。<br/>`type PrimaryTableRowValidateContext<T> = { result: TableRowValidateResult<T>[]; trigger: 'self' | 'parent' }`<br/><br/>`export type TableRowValidateResult<T> = PrimaryTableCellParams<T> & { errorList: AllValidateResult[]; value: any }`<br/> | N
onSelectChange | Function | | TS 类型:`(selectedRowKeys: Array<string | number>, options: SelectOptions<T>) => void`<br/>选中行发生变化时触发,泛型 T 指表格数据类型。两个参数,第一个参数为选中行 keys,第二个参数为更多参数,具体如下:`type = uncheck` 表示当前行操作为「取消行选中」;`type = check` 表示当前行操作为「行选中」; `currentRowKey` 表示当前操作行的 rowKey 值; `currentRowData` 表示当前操作行的行数据。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts)。<br/>`interface SelectOptions<T> { selectedRowData: Array<T>; type: 'uncheck' | 'check'; currentRowKey?: string; currentRowData?: T }`<br/> | N
onSortChange | Function | | TS 类型:`(sort: TableSort, options: SortOptions<T>) => void`<br/>排序发生变化时触发。其中 sortBy 表示当前排序的字段,sortType 表示排序的方式,currentDataSource 表示 sorter 排序后的结果,col 表示列配置。sort 值类型为数组时表示多字段排序。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts)。<br/>`interface SortOptions<T> { currentDataSource?: Array<T>; col: PrimaryTableCol }`<br/> | N

Expand All @@ -148,6 +151,8 @@ display-columns-change | `(value: CheckboxGroupValue)` | 确认列配置时触
drag-sort | `(context: DragSortContext<T>)` | 拖拽排序时触发,`data` 表示排序前的数据,`newData` 表示拖拽排序结束后的新数据,`sort=row` 表示行拖拽事件触发,`sort=col` 表示列拖拽事件触发。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts)。<br/>`interface DragSortContext<T> { currentIndex: number; current: T; targetIndex: number; target: T; data: T[]; newData: T[]; currentData?: T[]; e: SortableEvent; sort: 'row' | 'col' }`<br/><br/>`import { SortableEvent, SortableOptions } from 'sortablejs'`<br/>
expand-change | `(expandedRowKeys: Array<string | number>, options: ExpandOptions<T>)` | 展开行发生变化时触发,泛型 T 指表格数据类型。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts)。<br/>`interface ExpandOptions<T> { expandedRowData: Array<T> }`<br/>
filter-change | `(filterValue: FilterValue, context: { col?: PrimaryTableCol<T> })` | 过滤参数发生变化时触发,泛型 T 指表格数据类型
row-edit | `(context: PrimaryTableRowEditContext<T>)` | 行编辑时触发。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts)。<br/>`type PrimaryTableRowEditContext<T> = PrimaryTableCellParams<T> & { value: any }`<br/>
row-validate | `(context: PrimaryTableRowValidateContext<T>)` | 行编辑校验完成后出发。`result` 表示校验结果,`trigger=self` 表示编辑组件内部触发的校验,`trigger='parent'` 表示表格父组件触发的校验。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts)。<br/>`type PrimaryTableRowValidateContext<T> = { result: TableRowValidateResult<T>[]; trigger: 'self' | 'parent' }`<br/><br/>`export type TableRowValidateResult<T> = PrimaryTableCellParams<T> & { errorList: AllValidateResult[]; value: any }`<br/>
select-change | `(selectedRowKeys: Array<string | number>, options: SelectOptions<T>)` | 选中行发生变化时触发,泛型 T 指表格数据类型。两个参数,第一个参数为选中行 keys,第二个参数为更多参数,具体如下:`type = uncheck` 表示当前行操作为「取消行选中」;`type = check` 表示当前行操作为「行选中」; `currentRowKey` 表示当前操作行的 rowKey 值; `currentRowData` 表示当前操作行的行数据。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts)。<br/>`interface SelectOptions<T> { selectedRowData: Array<T>; type: 'uncheck' | 'check'; currentRowKey?: string; currentRowData?: T }`<br/>
sort-change | `(sort: TableSort, options: SortOptions<T>)` | 排序发生变化时触发。其中 sortBy 表示当前排序的字段,sortType 表示排序的方式,currentDataSource 表示 sorter 排序后的结果,col 表示列配置。sort 值类型为数组时表示多字段排序。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts)。<br/>`interface SortOptions<T> { currentDataSource?: Array<T>; col: PrimaryTableCol }`<br/>

Expand Down Expand Up @@ -260,6 +265,7 @@ component | \- | - | 组件定义,如:`Input` `Select`。对于完全自定
onEdited | Function | - | 编辑完成后,退出编辑模式时触发。TS 类型:`(context: { trigger: string; newRowData: T; rowIndex: number }) => void` | N
props | Object | - | 透传给组件 `edit.component` 的属性。TS 类型:`{ [key: string]: any }` | N
rules | Array | - | 校验规则。TS 类型:`FormRule[]`[Form API Documents](./form?tab=api)[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N
showEditIcon | Boolean | true | 是否显示编辑图标 | N

### TableTreeConfig

Expand Down
Loading

0 comments on commit 3bb0731

Please sign in to comment.