基于 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 进行二次封装,提供了更强大的列组管理功能,特别适合需要展示复杂表头结构的业务场景。组件设计灵活,支持多种渲染方式,能够满足不同的数据展示需求。

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

相关推荐
送鱼的老默3 小时前
学习笔记-JavaScript的原型和原型链
javascript
小纯洁w3 小时前
vue3.0 使用el-tree节点添加自定义图标造成加载缓慢的多种解决办法
前端·javascript·vue.js
叫我詹躲躲3 小时前
Vue 3 ref 与 reactive 选哪个?
前端·vue.js
程序员Sunday3 小时前
Vite 要收费啦?虚拟 DOM 要取消啦?尤雨溪这次玩了把大的!
前端·vue.js
云枫晖3 小时前
webpack系列-plugin
前端·webpack
wjs20243 小时前
CSS3 圆角
开发语言
颜颜yan_3 小时前
Rust impl块的组织方式:从基础到实践的深度探索
开发语言·后端·rust
啃火龙果的兔子3 小时前
前端八股文es6篇
前端·ecmascript·es6
困惑阿三3 小时前
ES6冷门API
前端·ecmascript·es6