可编辑表格组件ReEditTable

962 阅读9分钟

可编辑表格ReEditTable

组件实现基于 Vue3 + Element Plus + Typescript,同时引用 vueUse + lodash-es + tailwindCss (不影响功能,可忽略)

基于自封的分页表格组件ReTable进行的功能扩展,在 ReTableColumn 配置的基础上,结合ReForm一些相同的表单配置项,一同实现可编辑功能。支持多种编辑表格交互方式,如单个单元格编辑,整行编辑,或者全部行编辑;支持单元格校验,使用ElForm相同校验规则的配置项进行校验;同时,表格也支持滚动、分页功能。

校验方式支持整个表格校验,自动跳转首行校验失败的位置(分页也支持),也支持单行数据校验、单个单元格数据校验这三种校验方式。

由于行渲染表单控件未使用ElForm进行包裹,无法直接通过ElForm自带的校验功能进行数据校验,主要基于自己写的async-validate方法进行数据校验。目前只针对常见的rules配置规则进行遍历校验,如果不满足您的需求,你可以直接自己实现校验方法后替换方法即可。

可编辑表格不仅支持全量数据直接进入编辑,还支持单元格单独编辑或者单行单独编辑。【推荐】单行编辑,加上分页功能,能够解决大部分可编辑表格输入卡顿问题。

思路

基于ReTableColumn的配置项扩展,增加了一些同ReFormItem相似的配置项,利用ElTableColumn的formatter或者renderCell自定义渲染方式,动态渲染表单控件,因此需要基于配置以及编辑状态进行自定义渲染函数的构造。

增加了required、comp、childComp、rules、props等渲染表单控件的字段即可,原先已经支持options了(同ReFormItem用法一致,可以用于渲染一些下拉、单选钮组、多选框组),自带的slot插槽也可用于自定义表单控件渲染,同时还将当前行的编辑状态通过作用域插槽返回,可以用于控制自定义展示内容。

处理完表单控件渲染,需要区分一些交互方式,目前支持整个表格可编辑、单行编辑、单个单元格编辑等控制,同时单行编辑还区分自定义控制还是直接双击控制,单元格编辑只支持双击控制。

目前单行编辑(edit-trigger=row)、单个单元格编辑(edit-trigger=cell)采用鼠标左键双击开启编辑/关闭编辑的交互方式,如果使用自定义单行编辑(edit-trigger=custom),需要使用操作列来控制,可以直接使用自带的操作列也可以自定义,提供的expose方法足够自己控制编辑状态。

需要按列配置收集校验规格,通过数据逐行遍历校验,行数据基于列配置收集的校验规格逐个字段进行校验,因此可以清晰的构造三种校验方式:全量数据、单行、单个单元格。

除了上述最基本的功能处理外,还需要处理各种状态缓存,如编辑状态(区分按行、还是按单元格)、原始数据缓存(用于还原)、校验结果缓存(用于展示校验失败信息),既要支持增加、删除、判断是否存在等功能,还需要增加索引更新操作(如果删除某一行之后,需要更新受影响的缓存数据,否则会行渲染会出错)

其他一些功能点:自定义操作列的定义渲染,内置新增按钮的展示(支持页脚和头部两种方式)

image.png

image.png

难点

  • 索引的理解:如果是滚动表格,ElTable返回的索引是实际的数据索引,但如果是分页表格,ElTable返回的索引实际是当前页的索引,要正确数据响应,需要进行索引的转换,因此源码中存在大量的索引转换处理(normalizeIndex)。
  • 各种状态缓存维护
  • 单元格的自定义渲染函数构造
  • 提供rules规则校验方法

特殊点

  • ElTable双击事件,未返回索引信息,因此需要自行获取索引信息,目前采用两种方式:如果配置rowKey,则通过rowKey从数据中获取数据索引,如果是分页情况需要根据页码进行当前页的索引转换;如果没有rowKey,则通过DOM操作获取当前tr所在父节点的索引位置,注意,DOM获得的索引是渲染的索引(当前页的索引),需要转换成数据索引。

基础

基于ReTableColumn扩展了ReEditTableColumn,补充了一些类似ReFormItem的字段,可以方便理解配置,开启 editable 直接按可编辑状态进行行渲染,trigger将会失效,同时内置的操作列只会存在一个删除操作。

image.png

image.png

查看 /demo/table/edit-table-basic.md

:::warning 少量数据型的可编辑表格可以开启 editable 使得所有行可编辑,否则建议走按钮切换或者双击开启编辑交互。 :::

整行编辑

设置 edit-trigger="row" 开启行编辑交互,需要通过鼠标左键双击行进入编辑,编辑完成后双击行空白地方进行行校验,校验成功自动关闭,否则给出校验提示。默认会渲染操作列,也支持开启行编辑,如果不想要的话可以通过 render-action="false" 属性关闭。

image.png

查看 /demo/table/edit-table-row.md

自定义整行编辑

设置 edit-trigger="row"edit-trigger="custom" 开启行编辑交互,可以通过 render-action="false" 属性关闭默认的操作列渲染,通过类配置自己构建操作列进行自定义行编辑。

image.png

查看 /demo/table/edit-table-custom-row.md

单元格编辑

设置 edit-trigger="cell" 开启单元格编辑交互,需要通过鼠标左键双击单元格进入编辑,编辑完成后双击单元格空白地方进行单元格校验,校验成功后自动关闭,否则给出校验提示。

image.png

查看 /demo/table/edit-table-cell.md

自定义控件

同ReFormItem配置类似,需要指定slot插槽,在通过插槽进行自定义控件渲染。插槽增加 editable 区分单元格是否处于编辑状态,cellValue 表示单元格数据值,handler 表示单元格数据更新事件处理器

image.png

查看 /demo/table/edit-table-slot.md

ReEditTable属性

字段说明类型默认值
size可编辑表格尺寸"large" | "default" | "small""default"
stripe条纹表格booleanfalse
createNew提供返回新的一行创建函数,默认自动收集列配置中的defaultValue() => ReTableRow-
showAddBtn是否展示新增按钮booleantrue
addBtnPosition新增按钮展示位置"top" | "bottom""bottom"
addBtnProps新增按钮属性Partial<ButtonProps>-
addBtnDisabled新增按钮是否禁用booleanfalse
according是否限制每次只有一行/或一个单元格可以编辑booleanfalse
pageSize页大小number10
pagination是否开启分页booleanfalse
disabled可编辑表格是否禁用booleanfalse
editable可编辑表格是否所有单元格都直接进入编辑状态booleanfalse
confirmBeforeDelete删除行是否进行二次确认booleantrue
confirmMessage删除行进行二次确认提示文本string-
editTrigger触发编辑的交互方式"cell" | "row" | "custom""custom"
renderAction是否采用内置的操作列booleantrue
columns必填,可编辑表格列配置ReEditTableColumn[]-
rowKey数据主键,如果有建议配置,提供性能string-
ignoreCellValid是否忽略单元格编辑时触发校验,直接对整个编辑表格进行一次校验booleanfalse
scrollToError表格校验失败是否自动滚动到第一个校验错误行booleantrue
scrollIntoViewOptions滚动行为配置booleanfalse
maxHeight表格高度number-

除了上述属性之外,ReTable属性均支持,默认会被ReTable实例继承

:::warning 建议设置rowKey,可以提供组件渲染性能。组件实现过程中需要基于rowKey进行搜索,如果未提供,将会通过DOM操作的方式进行查找,会降低性能。 :::

ReEditTableColumn字段

字段说明类型默认值
required字段是否必填booleanfalse
editable字段是否可编辑booleanfalse
defaultValue表单字段默认值string-
defaultText表单字段默认展示占位符string"-"
comp表单控件string-
childComp子组件所使用组件string-
props表单控件属性配置Record<string, any>-
events表单控件事件监听Record<string, Function>-
rules表单字段校验规则Arrayable<FormItemRule>-
modelProp表单字段控件v-model关联属性string"modelValue"
modelEvent表单字段控件v-model关联事件string"update:modelValue"

除了上述字段之外,ReTableColumn字段均支持

ReEditTable事件

事件名说明格式
cell-dblclick鼠标左键双击某个单元格时触发(row: any, column: any, cell: HTMLTableCellElement, event: Event) => void
cell-contextmenu鼠标右键点击某个单元格时触发(row: any, column: any, cell: HTMLTableCellElement, event: Event) => void
row-dblclick鼠标左键双击某行时触发(row: any, column: any, event: Event) => void
row-contextmenu鼠标右键点击某行时触发(row: any, column: any, event: Event) => void
cell-change可编辑的单元格数据更新时触发(row: any, column: any, value: any, index: number) => void
scroll-to表格校验失败自动滚动到第一个校验失败的行时触发(index: number, callback?: Function) => void
update:data绑定数据更新时触发(data: Record<string, any>[]) => void

除了上述事件之外,ReTable支持的事件也支持,默认会被ReTable实例继承

ReEditTable插槽

插槽名说明
empty空状态展示
toolbox-left页头工具栏左侧内容插槽,可用于自定义新增按钮
toolbox-right页头工具栏右侧内容插槽,可用于自定义附加按钮
add-bottom-button页脚新增按钮插槽,用于自定义页脚的新增按钮,只有在 showAddBtnaddBtnPosition="bottom" 时有效

除了上述插槽之外,列配置项配置的插槽也支持。如果是自定义控件,列配置需要指定插槽

ReEditTable Expose

字段说明类型
reTableRefReTable组件实例InstanceType<typeof ReTable>
editData编辑表格数据Record<string, any>[]
normalizeIndex获取数据集索引,自定义操作列需要($index: number) => number
removeEditRows移除指定行编辑状态,自定义操作列需要($index: number) => void
removeRowCache移除指定行编辑缓存,自定义操作列需要($index: number) => void
existIndexEditCells判断数据行是否处在某个单元格处在编辑状态($index: number) => boolean
existIndexEditRows判断数据行是否处在编辑状态($index: number) => boolean
reset重置所有编辑状态() => void
toAdd增加一行() => void
toDelete删除指定行($index: number) => void
toEdit编辑指定行($index: number) => void
toEditCell编辑指定单元格($index: number, prop: string) => void
cancelEditRow取消指定行编辑状态($index: number) => void
cancelEditCell取消指定单元格编辑状态($index: number, prop: string) => void
validate整个编辑表格校验(callback?: (valid: boolean) => void) => void
validateRow指定行校验(index: number, callback?: (valid: boolean) => void) => void
validateCell指定单元格校验(index: number, prop: string, callback?: (valid: boolean) => void) => void

:::warning $index:表示当前行在展示的数据的索引,如果是分页,即为当前页的索引;index:表示当前行在整个数据中的索引,如果是分页需要自行从数据中获得索引 :::

源代码

Github

/components/ReTable/src/editor.vue

可以通过查看具体实现,如果遇到问题可以留言或者提出issue。

如果觉得对您有帮助的话,可以请小编瑞一下

WechatIMG6.jpg

IMG_2654.JPG