yudada-table
v1.0.2
Published
`YudadaTable` 是基于 **Vue3 + Element Plus** 的 `el-table` 二次封装组件,专注于「**配置化列定义** + **常用表格交互开箱即用**」:
Readme
简介
YudadaTable 是基于 Vue3 + Element Plus 的 el-table 二次封装组件,专注于「配置化列定义 + 常用表格交互开箱即用」:
- 完整支持:支持
el-table/el-table-column的绝大部分属性、事件和插槽。 - 增强多选:内置跨分页多选功能,支持选中记忆。
- 多级表头:通过
children字段即可配置多级列,零模板嵌套。 - 操作列、展开行、追加行:常用表格交互能力一站式集成。
- 分页封装:内置
el-pagination,统一管理分页状态和事件。
作者信息
- 作者:M.佑先生
- 邮箱:
[email protected]
安装与注册
安装
npm i YudadaTable或
yarn add YudadaTable说明:
YudadaTable依赖Element Plus,请确保你的项目中已经安装并全局引入了 Element Plus 以及它的样式文件。
# 如果还没有装过 Element Plus,需要先安装
npm i element-plus
# 或
yarn add element-plus全局挂载组件
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import YudadaTable from 'YudadaTable'
const app = createApp(App)
app.use(ElementPlus)
app.use(YudadaTable)
app.mount('#app')注册完成后即可在任意页面直接使用标签 <YudadaTable />(或 <yudada-table />)。
推荐使用步骤(快速上手指引)
- 安装依赖,并全局注册
Element Plus+ 引入其 CSS,再注册YudadaTable组件(见上文)。 - 准备表格数据
tableData:通常是接口返回的数据列表。 - 定义列配置
columns(核心):使用 JSON 形式定义每一列的prop、label、slotName、children等。 - 配置表格行为
tableConfig:是否显示多选、序号列、操作列、展开行、追加尾行等。 - 配置分页
paginationConfig(可选):在开启分页时,统一管理current、pageSize、total等字段。 - 在模板中引入
<YudadaTable />,通过props传入上述配置,并根据需要监听分页与多选等事件。
下方的「快速上手」示例即是按照以上步骤组合而成。
快速上手
<template>
<YudadaTable
stripe
border
show-summary
:summary-method="getSummaries"
:tableData="tableData"
:loading="loading"
:columns="tableColumns"
:tableConfig="tableConfig"
:paginationConfig="paginationConfig"
@page-size-change="onPageSizeChange"
@current-page-change="onCurrentPageChange"
ref="yudadaTableRef"
>
<!-- 自定义列 -->
<template #name="{ scope }">
<el-tag type="success">{{ scope.row.name }}</el-tag>
</template>
<!-- 自定义操作列 -->
<template #handler="{ scope }">
<el-button size="small" type="primary" @click="editRow(scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="deleteRow(scope.row)">删除</el-button>
</template>
</YudadaTable>
</template>
<script setup lang="js">
import { reactive, ref } from 'vue'
const loading = ref(false)
// 表格数据
const tableData = ref([])
// 列配置(重点:传 JSON)
const tableColumns = reactive([
{
label: '排名',
prop: 'ranking',
type: 'index',
width: 80,
index: (index) => index + 1
},
{
prop: 'name',
label: '姓名',
slotName: 'name' // 使用插槽渲染
}
])
// 表格基础配置
const tableConfig = reactive({
showSeletion: true, // 显示多选
showIndexColumn: true, // 显示序号列
showHandler: true, // 显示操作列
isCheckMemory: true // 跨页记忆勾选
})
// 分页配置
const paginationConfig = reactive({
current: 1,
pageSize: 10,
total: 0
})
function onPageSizeChange(size) {
paginationConfig.pageSize = size
}
function onCurrentPageChange(page) {
paginationConfig.current = page
}
function editRow(row) {
console.log('编辑', row)
}
function deleteRow(row) {
console.log('删除', row)
}
const yudadaTableRef = ref()
// 自定义合计方法(示例)
function getSummaries({ columns, data }) {
const sums = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '合计'
return
}
const values = data.map((item) => Number(item[column.property]))
if (!values.every((value) => Number.isNaN(value))) {
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr)
if (!Number.isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)
} else {
sums[index] = ''
}
})
return sums
}
</script>如何传入列的 JSON(columns)
columns 是一个数组,每一项对应一个 el-table-column,支持 el-table-column 的所有属性,并额外扩展:
slotName:自定义列内容的插槽名称(例如slotName: 'name'对应<template #name>)。children:子列数组,用于配置多级表头。
复杂列配置示例(节选自 examples/data.ts)
export const columns = [
{
label: '排名',
prop: 'ranking',
type: 'index',
width: 80,
index: (index) => index * 3
},
{
prop: 'name',
label: '名字',
filters: [
{ text: '李白2', value: '李白2' },
{ text: '李白4', value: '李白4' }
],
'filter-method': (value, row, column) => {
const property = column['property']
return row[property] === value
},
slotName: 'name'
},
{
prop: 'address',
label: '地址',
children: [
{
label: '省份',
prop: 'province',
align: 'center'
},
{
label: '城市',
prop: 'city',
align: 'center',
children: [
{
label: '区',
prop: 'area',
align: 'center'
},
{
label: '县',
prop: 'county',
align: 'center'
}
]
}
]
},
{
prop: 'amount',
label: '金额',
sortable: true
}
]在页面中直接传入:
<YudadaTable :columns="columns" />多级表头说明:只要某一项有
children数组,就会自动使用多级表头组件递归渲染。
如何获取表格全选/多选后的行数据
组件通过 原生事件 和 实例方法 两种方式操作和获取多选数据。
1. 通过原生事件获取选中行
组件支持 el-table 原生的 selection-change 事件,可以通过监听该事件获取当前页的选中行:
<YudadaTable
:tableData="tableData"
:columns="columns"
:tableConfig="{ showSeletion: true, isCheckMemory: true }"
@selection-change="onSelectionChange"
/>
<script setup lang="js">
import { ref } from 'vue'
const selection = ref([])
function onSelectionChange(rows) {
selection.value = rows
console.log('当前选中行:', rows)
}
</script>注意:如果需要获取跨页选中的行,可以通过监听
selection-change事件并自行维护选中状态,或者使用el-table原生的reserve-selection属性(通过tableConfig.isCheckMemory配置)。
2. 通过 ref 操作多选(全选 / 取消全选)
组件内部暴露了若干方法(见下方"实例方法"),跟 el-table 的多选方法保持一致:
clearSelection():清空所有勾选。toggleRowSelection(row, selected?):切换单行勾选。toggleAllSelection():切换全选/全不选。
<template>
<YudadaTable
ref="xmwTableRef"
:tableData="tableData"
:columns="columns"
:tableConfig="{ showSeletion: true }"
@selection-change="onSelectionChange"
/>
<el-button @click="clearAll">清空多选</el-button>
<el-button @click="toggleAll">切换全选/全不选</el-button>
</template>
<script setup lang="js">
import { ref } from 'vue'
const xmwTableRef = ref()
const selection = ref([])
// 监听原生 selection-change 事件获取选中行
function onSelectionChange(rows) {
selection.value = rows
console.log('当前选中行:', rows)
}
function clearAll() {
xmwTableRef.value?.clearSelection()
}
function toggleAll() {
xmwTableRef.value?.toggleAllSelection()
}
</script>注意:如果需要获取跨页选中的行,可以通过监听
selection-change事件并自行维护选中状态,或者使用el-table原生的reserve-selection属性(通过tableConfig.isCheckMemory配置)。
如何取消合计列(合计行)
组件内部通过 v-bind="$attrs" 将属性透传给 el-table,因此合计行与 Element Plus 原生用法保持一致:
- 开启合计:增加
show-summary属性(或:show-summary="true")。 - 自定义合计规则:传入
summary-method。 - 取消合计:删除
show-summary属性,或者设置为false。
<!-- 开启合计 -->
<YudadaTable
:tableData="tableData"
:columns="columns"
show-summary
:summary-method="getSummaries"
/>
<!-- 取消合计(两种写法任选其一) -->
<YudadaTable
:tableData="tableData"
:columns="columns"
/>
<YudadaTable
:tableData="tableData"
:columns="columns"
:show-summary="false"
/>Table Props(封装组件本身)
除表中列出内容外,还支持所有
el-table原生属性(通过$attrs透传)。
| 参数 | 说明 | 类型 | 默认值 |
| :----------------- | :---------------------------------------- | :-----: | :----: |
| tableData | 表格数据 | Array | - |
| columns | 列配置,详情见「Column 属性」 | Array | - |
| loading | 加载状态 | Boolean | false |
| tableConfig | 表格扩展配置项,详情见下方 tableConfig | Object | - |
| showPagination | 是否显示分页 | Boolean | true |
| paginationConfig | 分页配置项,详情见下方 paginationConfig| Object | - |
Column 属性
除下表外,支持所有
el-table-column属性。
| 参数 | 说明 | 类型 | 默认值 |
| :--------- | :----------------------------- | :-------------------- | :----: |
| slotName | 启用插槽渲染该列,值为插槽名称 | Boolean / String | false |
| children | 多级表头子列配置 | Array<ColumnConfig> | - |
tableConfig 配置项
除下表字段外,其余字段会直接合并到内部
el-table上。
| 参数 | 说明 | 类型 | 默认值 |
| :---------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------: | :------------------------------------------: |
| rowKey | 行数据的 Key,用来优化 Table 渲染;在使用多选或树形数据时必填。String 类型支持多层访问:user.info.id,不支持 user.info[0].id,此种情况请使用 Function。 | Function(row)/String | 'id' |
| showSeletion | 是否支持多选 | Boolean | false |
| showIndexColumn | 是否显示序号列 | Boolean | false |
| indexLabel | 自定义索引列表头名 | String | '序号' |
| isCheckMemory | 是否需要跨页勾选记忆 | Boolean | false |
| showHandler | 是否显示操作列 | Boolean | false |
| showExpand | 是否是展开行 | Boolean | false |
| showAppend | 是否在表格最后一行之后插入内容(若有合计行,则在合计行之上) | Boolean | false |
| appendLabel | 追加列默认显示的文字 | String | '自定义' |
| handlerConfig | 操作列配置,showHandler 为 true 时有效,会与默认 { label: '操作', minWidth: 80, fixed: 'right' } 合并 | Object | { label: '操作', minWidth: 80, fixed: 'right' } |
Page(paginationConfig)配置项
除下表外,支持所有
el-pagination属性。
| 参数 | 说明 | 类型 | 默认值 |
| :---------- | :--------------------- | :----: | :--------------------------------------- |
| total | 条目数 | number | 0 |
| current | 当前页数 | number | 1 |
| pageSize | 每页显示条目个数 | number | 10 |
| pageSizes | 每页显示个数选择器选项 | Array | [10, 20, 30, 50] |
| layout | 分页组件布局 | String | "total, sizes, prev, pager, next, jumper" |
Slot 插槽
| name | 说明 | 参数 |
| :---------------- | :------------------------------------------------------------------- | :----------------------: |
| handler | 自定义操作列的内容(需 tableConfig.showHandler = true) | { scope } |
| expand | 自定义展开行内容(需 tableConfig.showExpand = true) | { props } |
| append | 自定义尾部追加内容(需 tableConfig.showAppend = true) | { props } |
| indexHeader | 自定义序号列表头内容(需 tableConfig.showIndexColumn = true) | { scope } |
| 动态列插槽 | 任意 column.slotName='xxx' 对应 <template #xxx="{ scope }" /> | { scope } |
Events 事件
除下表外,支持所有
el-table事件(如selection-change、row-click等)。
| 事件名称 | 说明 | 参数 |
| :-------------------- | :----------------------------------------- | :------: |
| current-page-change | current 改变时触发(分页当前页改变) | 当前页 |
| page-size-change | pageSize 改变时触发(每页条数改变) | 每页条数 |
表格实例方法(通过 ref 调用)
组件通过 defineExpose 暴露了内部 el-table 常用方法,可以方便地在业务中直接调用:
clearSelection():清空多选状态。toggleRowSelection(row, selected?):切换某行的勾选状态。toggleAllSelection():切换全选 / 全不选。toggleRowExpansion(row, expanded?):切换某行展开状态。setCurrentRow(row?):设置当前高亮行,不传参数则取消高亮。clearSort():清空排序条件,恢复原始数据顺序。clearFilter(columnKeys?):清空过滤条件。doLayout():手动重新布局 Table。sort(prop, order):手动排序,order为'ascending' | 'descending' | null。
<template>
<YudadaTable
ref="yudadaTableRef"
:tableData="tableData"
:columns="columns"
/>
<el-button @click="sortAmountDesc">按金额倒序</el-button>
</template>
<script setup lang="js">
import { ref } from 'vue'
const yudadaTableRef = ref()
function sortAmountDesc() {
yudadaTableRef.value?.sort('amount', 'descending')
}
</script>时间列处理(时间戳 / 年月日字符串)
组件本身不会强行帮你格式化时间,而是透传 el-table-column 的 formatter 和插槽能力,方便你根据业务自定义“时间戳、年月日字符串”等多种格式。
推荐方式一:使用列的 formatter(只做格式化时推荐)
在业务项目中定义一个通用的时间格式化函数,例如:
// utils/date.ts
export function formatTime(value: any) {
if (!value) return ''
let date: Date
// 数字或纯数字字符串,当作时间戳
if (typeof value === 'number' || /^\d+$/.test(String(value))) {
date = new Date(Number(value))
} else {
// 普通日期字符串,例如 "2024-01-01 10:20:30"
date = new Date(value)
}
if (Number.isNaN(date.getTime())) return String(value)
const pad = (n: number) => (n < 10 ? '0' + n : n)
const y = date.getFullYear()
const m = pad(date.getMonth() + 1)
const d = pad(date.getDate())
const hh = pad(date.getHours())
const mm = pad(date.getMinutes())
const ss = pad(date.getSeconds())
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
}在列配置中使用 formatter:
import { formatTime } from '@/utils/date'
const columns = [
{
prop: 'createdAt',
label: '创建时间',
formatter: (_row: any, _column: any, cellValue: any) => formatTime(cellValue)
}
]由于 YudadaTable 内部使用了:
<el-table-column v-bind="column" />所以这里的 formatter 会直接传递给 Element Plus 原生的 el-table-column 生效。
推荐方式二:使用插槽渲染时间列(需要复杂 DOM 时)
当你不仅要格式化时间,还要配合图标、颜色、按钮等复杂展示时,可以给列配置一个 slotName,然后在插槽中手动调用 formatTime:
// 列配置
const columns = [
{
prop: 'createdAt',
label: '创建时间',
slotName: 'createdAtCol'
}
]<template>
<YudadaTable :tableData="tableData" :columns="columns">
<template #createdAtCol="{ scope }">
<span class="time-text">{{ formatTime(scope.row.createdAt) }}</span>
<!-- 这里可以根据业务加图标、标签等 -->
<el-tag v-if="scope.row.isNew" type="success">新</el-tag>
</template>
</YudadaTable>
</template>建议:仅做格式化时优先使用
formatter,需要复杂结构时再用插槽。两种方式都完全由业务侧控制,组件本身保持通用、无侵入。
