UseElTable - 表格
组件介绍
UseElTable 是基于 Element Plus 的 ElTable 二次封装的表格组件,专注于标准化表格列配置、单元格数据格式化、统一操作栏管理,同时标准化扩展配置项管理,完整兼容原生 ElTable 核心属性、事件、插槽,可直接替换原生 ElTable 使用,大幅降低表格列定义、单元格格式化、操作按钮重复开发成本。
核心能力
- 标准化列配置管理
通过统一 columns 配置数组批量定义表格列,支持列标题、绑定字段、宽度、对齐、固定列、显隐控制、单元格格式化回调等配置,减少页面重复编写 el-table-column 模板代码,同时保留自定义插槽扩展能力适配特殊单元格渲染。
- 标准化单元格数据格式化能力
内置通用单元格数据转换逻辑,支持时间、金额、布尔、枚举映射等常用格式化规则,支持自定义格式化函数;空单元格统一配置兜底占位文本,避免原始空值展示不友好,格式化规则可通过全局扩展配置统一预设。
- 统一操作栏封装
内置 actionColumn 配置统一管理表格右侧操作列,操作按钮完整复用 UseElButton 全部内置防抖、二次确认能力,支持自定义操作栏宽度、对齐方式,统一项目内所有表格操作栏视觉与交互规范。
- 灵活的配置优先级管理
所有扩展配置遵循「组件局部配置 > 全局默认配置 > 内置默认值」优先级规则,组件传入的 extConfig 优先覆盖 defaultExtConfig 中的默认配置(如空数据兜底文本、操作栏默认宽度),未配置时自动兜底,兼顾全局统一与局部灵活调整。
- 原生表格完全兼容
底层完整透传 ElTable 全部原生 props、事件、插槽,原生多选、树形表格、展开行、合计行等高级特性全部保留,原有原生表格写法无需改动,可直接替换原生 ElTable,无迁移成本,同时补充原生表格缺失的列配置、格式化、统一操作栏能力。
- 统一加载与空状态管控
内置 loading、空数据展示相关扩展配置,支持自定义加载提示、空状态文案,未自定义时读取全局默认扩展配置兜底样式,统一项目内所有表格加载、无数据场景用户体验。
- 扩展配置标准化
通过 ExtConfig 接口标准化列、格式化、操作栏、空状态等扩展配置项,提供 defaultExtConfig 全局默认扩展配置,业务侧可全局统一覆盖通用表格配置,保证项目内表格扩展配置规范统一。
- 样式兼容与问题修复
内置配套样式兼容逻辑,修复表格搭配弹窗、抽屉组件时层级覆盖、滚动布局挤压、固定列样式错位等常见问题,保证表格在不同页面布局、嵌套容器下展示一致性。
- 安全的生命周期管理
组件挂载时初始化列配置、格式化缓存;卸载时自动解绑内部回调、清空临时状态缓存、移除页面监听,避免内存泄漏,保证组件在动态路由、弹窗、标签页频繁销毁重建场景下运行稳定。
使用
Props
import type { PropType } from 'vue'
import type { ExtConfig, TableColumn } from './types'
import type { DictMap, DictProps } from '@/types'
/**
* 组件props
*/
export default {
/**
* 表格列 必传
* 注意:常规场景下列配置为静态值无需响应式;但本组件提供了 minWidth 自动计算能力并会修改列对象,
* 因此 tableColumns 必须用 ref/reactive 包裹,否则视图无法同步更新最小宽度。
*/
tableColumns: {
type: Array as PropType<TableColumn[]>,
required: true
},
/**
* 表格数据 必传
*/
tableData: {
type: Array as PropType<Record<string, unknown>[]>,
required: true
},
/**
* 表格loading
*/
tableLoading: {
type: Boolean,
default: false
},
/**
* 表格列排列方式 默认center
*/
tableColumnAlign: {
type: String,
default: 'center',
validator: (val: string) => ['left', 'center', 'right'].includes(val)
},
/**
* 字典映射 数据结构为{ tableColumns[][label | useDict | useDict.key]: Array<{ label: string, value: any }> }
*/
dictMap: {
type: Object as PropType<DictMap>,
default: () => ({})
},
/**
* 字典属性 默认为{ value: 'value', label: 'label',children:'children' },可通过全局配置进行设置,为适配全局配置此处不再设置默认值
*/
dictProps: {
type: Object as PropType<DictProps>,
default: () => ({})
},
/**
* 当前页数
*/
currentPage: {
type: Number,
default: 1
},
/**
* 当前页码
*/
pageSize: {
type: Number,
default: 10
},
/**
* 当内容过长被隐藏时是否显示tooltip 默认是
*/
showOverflowTooltip: {
type: Boolean,
default: true
},
/**
* 表头列样式
*/
headerCellStyle: {
type: Object as PropType<Record<string, string>>,
default: () => ({
backgroundColor: 'var(--el-fill-color-light)',
color: 'var(--el-table-header-text-color)'
})
},
/**
* 扩展配置 如【序号/复选单选/展开列/分页】等
*/
extConfig: {
type: Object as PropType<ExtConfig>,
default: () => ({})
}
}Types
import type { Component, ExtractPropTypes } from 'vue'
import type { EditAttrs, GlobalConfig, UseDict } from '@/types'
import componentProps from './props'
/**
* props类型
*/
export type Props = ExtractPropTypes<typeof componentProps>
/**
* emits类型
*/
export type Emits = {
/** dictKeys事件 */
(e: 'onDictKeys', value?: string[]): void
/** 选中数据更新事件 v-model:selectionData */
(e: 'update:selectionData', selectionData: any[]): void
/** 当前行更新事件 v-model:currentRow */
(e: 'update:currentRow', currentRow: any): void
/** 当前页码更新事件 v-model:currentPage */
(e: 'update:currentPage', currentPage: number): void
/** 每页条数更新事件 v-model:pageSize */
(e: 'update:pageSize', pageSize: number): void
}
/**
* EditableCell和SpanVue组件的props接口
*/
export interface EditableCellAndSpanVueProps {
/** 行数据 */
row: Record<string, any>
/** 表格配置项 */
item: TableColumn
/** 合并后的props */
mergedProps: Props
/** 全局配置 */
globalConfig: GlobalConfig
}
/**
* 表头配置接口
*/
export interface Header {
/** 表头具名插槽 为true则在模板代码中添加`<template #prop-header="{ item }"></template>`即可,可传入string自定义具名插槽名称 */
slot?: boolean | string
/** 表头是否必填 必填表头默认在表头名称前添加*号 */
required?: boolean
/** 必填表头*号位置 默认为before */
asteriskPosition?: 'before' | 'after'
}
/**
* 编辑配置接口
*/
export interface Edit {
/** 组件 */
component: Component
/** 属性 */
attrs?: EditAttrs
}
/**
* tableColumn接口
*/
export interface TableColumn {
/** 表格列的标签 */
label?: string
/**
* 表格列的属性 多级表头的父级表头可不传
*/
prop?: string
/**
* 使用字典
* 如为boolean则将label作为dictMap的key
* 如为string或dict.data为string则将dict或dict.data作为dictMap的key
*/
useDict?: boolean | string | UseDict
/** 表格列的宽度 */
width?: string | number
/** 表格列的最小宽度 */
minWidth?: string | number
/** 是否显示表格列 */
show?: boolean
/** 表格列的排列方式 */
align?: string
/** 表格列是否固定 */
fixed?: boolean | string
/** 表格列是否开启排序 */
sortable?: boolean
/** 表格列溢出是否显示省略号 */
showOverflowTooltip?: boolean
/** 表格列扩展配置 */
extConfig?: {
/** 表头配置 */
header?: Header
/** 编辑配置 */
edit?: Edit
/** 过滤器 */
formatter?: Function
/** 类名 */
class?: string | string[]
/** 样式 */
style?: string | Record<string, unknown>
/** 插槽 为true则在模板代码中添加`<template #prop="{ row }"></template>`即可,可传入string自定义具名插槽名称 */
slot?: boolean | string
}
/** 表格列的子表格列 */
children?: TableColumn[]
}
/**
* 选择器配置项
*/
export interface Selection {
/** 选择器的标签 type为CHECKBOXRADIO、RADIO时表头全选复选框的文本,不设置则为空显示 */
label?: string
/** 选择类型 可选值:CHECKBOX(复选) | CHECKBOXRADIO(复选框单选) | RADIO(单选) */
type?: 'CHECKBOX' | 'CHECKBOXRADIO' | 'RADIO'
/** 选择器的列宽 */
width?: number
/** 选中数据的唯一键 对应tableData中的唯一键 如id */
key?: string
/** 允许通过点击行触发单选/复选 默认否 PS:默认不高亮当前行,若需高亮当前行,只需给UseElTable组件设置highlightCurrentRow属性即可 */
enableRowClick?: boolean
/** 决定当前行复选框是否可以勾选 传入function,如果是简单禁用逻辑推荐优先使用disabledConfig配置项,复杂逻辑才建议使用本配置项 */
selectable?: Function
/** 禁用配置 可传对象或对象数组 */
disabledConfig?:
| Record<string, string | number | string[] | number[]>
| Array<{ key: string; value: string | number | string[] | number[] }>
/** 选择器的排列方式 */
align?: string
/** 选择器是否固定 */
fixed?: boolean
}
/**
* UseElTable的extConfig接口
*/
export interface ExtConfig {
/** 额外表头配置项 */
extraHeader?: {
/** 是否显示边框线 默认和el-table的border保持一致 */
border?: boolean
/** 额外表头类名 */
class?: string
/** 额外表头样式对象 */
style?: { padding?: string; borderBottom?: string }
}
/** 模式配置项 */
mode?: {
/** 模式类型 可选值:PAGE(页面) | MODAL(弹窗) */
type?: 'PAGE' | 'MODAL'
/** 表格高度 不设置则默认高度自适应,该配置项设置的是UseELTable组件整体高度,非ElTable组件的高度 */
height?: string
/** 表格高度自适应表格底部预留偏移 该配置项由UseElConfigProvider组件统一提供默认值 */
bottomOffset?: number
}
/** 选择器配置项 绑定v-model:selectionData="selectionData"则开启选择器 不显式设置type则默认为CHECKBOX复选 */
selection?: Selection
/** 序号列配置项 */
index?: {
/** 序号列表头文本 不显式设置则不显示序号列 */
label?: string
/** 是否连续的,默认是,即第二页的序号根据第一条最后一个序号进行延续 */
isContinuous?: boolean
/** 序号列的列宽 */
width?: number
/** 序号列的排列方式 */
align?: string
/** 序号列是否固定 */
fixed?: boolean
}
/** 展开列配置项 */
expand?: {
/** 是否显示展开列 */
show?: boolean
/** 展开列宽度 */
width?: number
}
/** 操作列配置项 */
operation?: {
/** 操作列文案 显式设置则开启操作列 */
label?: string
/** 操作列列宽 */
width?: number
/** 操作列是否固定 */
fixed?: string
}
/** 分页器配置项 */
pagination?: {
/** 分页总数 为-1时不显示分页器 */
total?: number
/** 分页器与表格的间距 */
marginTop?: number
/** 分页器位置 */
position?: 'left' | 'center' | 'right'
/** 页码尺寸数组 */
pageSizes?: number[]
/** 是否显示分页器背景 */
background?: boolean
/** 分页器布局 */
layout?: string
/** 分页方法 显式设置则在组件内部自动处理分页逻辑 */
func?: Function
}
}DefaultExtConfig
import type { ExtConfig } from './types'
/**
* 默认扩展配置
*/
export default {
extraHeader: {
style: {
padding: '10px',
borderBottom: '1px solid var(--el-border-color-light)'
}
},
mode: { type: 'PAGE' },
selection: { width: 40, enableRowClick: false, align: 'center', fixed: true },
index: { width: 55, align: 'center', fixed: true, isContinuous: true },
expand: { show: false },
operation: { width: 128, fixed: 'right' },
pagination: {
total: -1,
marginTop: 20,
position: 'right',
pageSizes: [10, 20, 30, 40, 50],
background: true,
layout: 'total, sizes, prev, pager, next, jumper'
}
} satisfies ExtConfigExpose
defineExpose({ validRequired })