在前端开发中,表格是展示数据的常用组件,而复杂的业务场景往往需要用到多级表头。本文将介绍一款基于 Element Plus 封装的 TableColumnGroup 组件,该组件支持嵌套列组、自定义渲染、条件渲染等功能,能满足大多数复杂表格的展示需求。
组件功能特点
- 支持多级嵌套列组,轻松实现复杂表头结构
- 提供灵活的单元格渲染方式:默认渲染、自定义组件渲染、条件渲染
- 支持表格列的固定、宽度设置、对齐方式配置
- 内置数字格式化功能,支持千分制显示和单位转换
- 支持自定义样式类名,方便进行样式调整
组件参数说明
|--------------|----------------|------|---------------------------------------|
| 参数名 | 类型 | 默认值 | 说明 |
| label | String | - | 列组的标题 |
| type | String | '' | 列的类型,同 Element Plus 的 el-table-column |
| className | String | - | 列组的样式类名 |
| columns | Array | [] | 普通列配置数组,当没有嵌套列组时使用 |
| nestedGroups | Array | [] | 嵌套列组配置数组 |
| groupFixed | String/Boolean | null | 列组是否固定,同 Element Plus 的 fixed 属性 |
| groupWidth | String/Number | - | 列组的宽度 |
| groupProp | String | - | 列组对应的属性名 |
| treeProps | Object | null | 树形表格配置 |
| rowKey | String | - | 行数据的唯一标识 |
columns 数组元素配置
columns 数组中的每个元素可配置以下属性:
|-------------------|----------------|---------------------------|
| 属性名 | 类型 | 说明 |
| align | String | 单元格内容对齐方式,默认 'center' |
| label | String | 列标题 |
| prop | String | 对应行数据的属性名 |
| width | String/Number | 列宽度 |
| className | String | 列的样式类名,默认使用父组件的 className |
| fixed | String/Boolean | 列是否固定 |
| customRender | Component | 自定义渲染组件 |
| customRenderProps | Object | 传递给自定义渲染组件的属性 |
| conditionalRender | Function | 条件渲染函数,返回布尔值决定是否显示内容 |
| unit | String | 数据单位,用于格式化显示 |
使用示例
1. 基础使用(普通列)
javascript
<template>
<el-table :data="tableData">
<TableColumnGroup
:columns="[
{ label: '姓名', prop: 'name' },
{ label: '年龄', prop: 'age', unit: '岁' },
{ label: '邮箱', prop: 'email' }
]"
/>
</el-table>
</template>
2. 嵌套列组
javascript
<template>
<el-table :data="tableData">
<TableColumnGroup label="基本信息">
<TableColumnGroup
:columns="[
{ label: '姓名', prop: 'name' },
{ label: '年龄', prop: 'age', unit: '岁' }
]"
/>
</TableColumnGroup>
<TableColumnGroup label="联系方式">
<TableColumnGroup
:nestedGroups="[
{
label: '电话',
columns: [
{ label: '手机', prop: 'phone' },
{ label: '座机', prop: 'landline' }
]
},
{
label: '网络',
columns: [
{ label: '邮箱', prop: 'email' },
{ label: '网址', prop: 'website' }
]
}
]"
/>
</TableColumnGroup>
</el-table>
</template>
3. 自定义渲染
javascript
<template>
<el-table :data="tableData">
<TableColumnGroup
:columns="[
{ label: '姓名', prop: 'name' },
{
label: '状态',
prop: 'status',
customRender: StatusTag,
customRenderProps: { colors: { active: 'green', inactive: 'gray' } }
}
]"
/>
</el-table>
</template>
<script setup>
import StatusTag from './StatusTag.vue'
</script>
4. 条件渲染
javascript
<template>
<el-table :data="tableData">
<TableColumnGroup
:columns="[
{ label: '姓名', prop: 'name' },
{
label: '业绩',
prop: 'performance',
unit: '元',
conditionalRender: (row) => row.performance > 0
}
]"
/>
</el-table>
</template>
完整代码实例
javascript
<!-- TableColumnGroup.vue -->
<template>
<el-table-column align="center" :label="label" :type="type" :class-name="className" :fixed="groupFixed"
:width="groupWidth" :prop="groupProp">
<!-- 支持嵌套列组 -->
<template v-if="hasNestedGroups">
<TableColumnGroup v-for="(nestedGroup, nestedIndex) in nestedGroups" :key="nestedIndex" v-bind="nestedGroup" />
</template>
<!-- 普通列 -->
<template v-else>
<el-table-column v-for="col in columns" :key="col.prop" :align="col.align || 'center'" :label="col.label"
:prop="col.prop" :width="col.width" :class-name="col.className || className" :fixed="col.fixed">
<template #default="scope">
<span>
<!-- 支持自定义渲染 -->
<template v-if="col.customRender">
<component :is="col.customRender" :row="scope.row" :value="scope.row[col.prop]"
v-bind="col.customRenderProps" />
</template>
<template v-else-if="col.conditionalRender">
<!-- 条件渲染 -->
<span v-if="col.conditionalRender(scope.row)">
{{ formatNumberWithUnit(scope.row[col.prop], col.unit) }}
</span>
<span v-else class="hidden-column">-</span>
</template>
<template v-else>
<!-- 数字类型格式化:千分制+两位小数 -->
{{ formatNumberWithUnit(scope.row[col.prop], col.unit) }}
</template>
</span>
</template>
</el-table-column>
</template>
</el-table-column>
</template>
<script setup>
import { computed } from 'vue'
import { formatNumberWithUnit } from '@/utils/validate'
const props = defineProps({
label: String,
type: {
type: String,
default: '',
},
className: String,
// 普通列配置
columns: {
type: Array,
default: () => [],
},
// 嵌套列组配置
nestedGroups: {
type: Array,
default: () => [],
},
groupFixed: {
type: [String, Boolean],
default: null,
},
groupWidth: [String, Number],
groupProp: String,
// 树形表格配置
treeProps: {
type: Object,
default: null,
},
rowKey: String,
})
// 判断是否有嵌套列组
const hasNestedGroups = computed(() => {
return props.nestedGroups && props.nestedGroups.length > 0
})
</script>
<style lang="scss">
.el-table__row.level-1 {
background-color: #ffffff !important;
}
.el-table__row.level-2 {
background-color: #f8f3c3 !important;
}
.el-table__row.level-3 {
background-color: #fcd787 !important;
}
.el-table__row:hover>td {
background-color: #e9e9e9 !important;
}
.hidden-column {
color: #ccc;
font-style: italic;
}
</style>
模板使用
javascript
<el-table v-loading="loading" :data="oaBusinessMetricList" border max-height="660" row-key="id"
scrollbar-always-on :fit="true" resizable @selection-change="handleSelectionChange">
<el-table-column align="center" type="selection" width="55" fixed="left" />
<!-- 使用 TableColumnGroup 组件渲染列组 -->
<TableColumnGroup v-for="group in columnGroups" :key="group.key" v-bind="group" />
<!-- 操作列 -->
<el-table-column align="center" class-name="small-padding fixed-width blueInfoHeader" fixed="right" label="操作"
width="120">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button v-hasPerm="['oa:oaBusinessMetric:edit']" icon="Edit" link type="primary"
@click="handleUpdate(scope.row)" />
</el-tooltip>
</template>
</el-table-column>
</el-table>
javascript
const {
getColumns,
getColumnGroups,
} = useOaBusinessMetric();
// 获取列组配置并生成列组数据
const columnGroups = computed(() =>
getColumnGroups.value.map(group => ({
...group,
columns: getColumns(group.columnKey)
}))
);
样式说明
组件内置了一些基础样式,可通过自定义类名进行覆盖:
- 不同层级行的背景色:.el-table__row.level-1、.el-table__row.level-2、.el-table__row.level-3
- 行 hover 样式:.el-table__row:hover>td
- 条件渲染隐藏时的样式:.hidden-column(灰色斜体)
可根据实际需求在项目中自定义这些样式类。
总结
TableColumnGroup 组件通过对 Element Plus 的 el-table-column 进行二次封装,提供了更强大的列组管理功能,特别适合需要展示复杂表头结构的业务场景。组件设计灵活,支持多种渲染方式,能够满足不同的数据展示需求。
希望本文能帮助大家更好地理解和使用这个组件,如有任何问题或建议,欢迎在评论区留言讨论。
