基于 Element Plus 的 TableColumnGroup 组件使用说明

在前端开发中,表格是展示数据的常用组件,而复杂的业务场景往往需要用到多级表头。本文将介绍一款基于 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 进行二次封装,提供了更强大的列组管理功能,特别适合需要展示复杂表头结构的业务场景。组件设计灵活,支持多种渲染方式,能够满足不同的数据展示需求。

希望本文能帮助大家更好地理解和使用这个组件,如有任何问题或建议,欢迎在评论区留言讨论。

相关推荐
wjs20243 小时前
DOM CDATA
开发语言
Tingjct3 小时前
【初阶数据结构-二叉树】
c语言·开发语言·数据结构·算法
2601_949809593 小时前
flutter_for_openharmony家庭相册app实战+我的Tab实现
java·javascript·flutter
Up九五小庞4 小时前
开源埋点分析平台 ClkLog 本地部署 + Web JS 埋点测试实战--九五小庞
前端·javascript·开源
猷咪4 小时前
C++基础
开发语言·c++
IT·小灰灰4 小时前
30行PHP,利用硅基流动API,网页客服瞬间上线
开发语言·人工智能·aigc·php
快点好好学习吧4 小时前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
秦老师Q4 小时前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
烟锁池塘柳04 小时前
解决Google Scholar “We‘re sorry... but your computer or network may be sending automated queries.”的问题
开发语言
是誰萆微了承諾4 小时前
php 对接deepseek
android·开发语言·php