vxe-table 自定义表头合并:灵活合并任意列头

在实际项目中,默认的多级树形分组列头可能无法满足复杂报表的展示需求。vxe-table 提供了 show-custom-header 配置项,允许你完全自定义表头结构,实现任意行列的合并效果(类似 Excel 中的跨列居中、跨行合并)。

需要注意:启用自定义表头合并后,被合并的列将不支持拖拽调整列宽(因为合并后的列在视觉上不再是一列,而是多个列的集合)。此外,自定义合并的配置需要手动维护合并规则(mergeHeaderCells)。

参数

配置项 类型 说明
showCustomHeader Boolean 开启自定义表头模式。默认为 false,此时表头为树形分组结构;设置为 true 后,表头完全由 mergeHeaderCells 和 columns 共同决定。
mergeHeaderCells Array 合并规则数组,每个对象描述一个合并单元格的位置和跨度。格式:{ row: 0, col: 0, rowspan: 2, colspan: 1 }。
columns Array 列定义。即使在自定义合并模式下,仍需定义所有基础列字段,供数据渲染使用。

原理:当 showCustomHeader: true 时,表头不再自动根据 columns 的 children 生成层级,而是完全依据 mergeHeaderCells 指定的合并规则来渲染。你需要为每一个基础列(叶子列)指定它在表头矩阵中的位置(row 和 col),并通过 rowspan / colspan 合并相邻单元格。

代码

image

<template>
  <div>
    <vxe-button @click="setMerge1">设置合并1</vxe-button>
    <vxe-button @click="setMerge2">设置合并2</vxe-button>
    <vxe-button status="success" @click="saveMergeData">获取合并规则</vxe-button>

    <vxe-grid ref="gridRef" v-bind="gridOptions"></vxe-grid>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'

const gridRef = ref()

const gridOptions = reactive({
  border: true,
  showCustomHeader: true,
  height: 400,
  mergeHeaderCells: [
    { row: 0, col: 0, rowspan: 2, colspan: 1 },
    { row: 0, col: 1, rowspan: 2, colspan: 1 },
    { row: 0, col: 2, rowspan: 1, colspan: 2 },
    { row: 0, col: 4, rowspan: 1, colspan: 2 },
    { row: 1, col: 6, rowspan: 1, colspan: 2 },
    { row: 0, col: 8, rowspan: 2, colspan: 1 }
  ],
  columns: [
    { type: 'seq', width: 70 },
    { field: 'name', title: 'Name' },
    {
      title: 'Group1',
      field: 'group1',
      headerAlign: 'center',
      children: [
        { field: 'sex', title: 'Sex' },
        { field: 'age', title: 'Age' }
      ]
    },
    {
      field: 'group3',
      title: 'Group3',
      headerAlign: 'center',
      children: [
        { field: 'attr5', title: 'Attr5' },
        { field: 'attr6', title: 'Attr6' }
      ]
    },
    {
      field: 'group6',
      title: 'Attr3',
      children: [
        { field: 'attr3', title: 'Group8', headerAlign: 'center' }
      ]
    },
    {
      field: 'group8',
      title: 'Attr4',
      children: [
        { field: 'attr4', title: 'Attr4' }
      ]
    },
    { field: 'address', title: 'Address' }
  ],
  data: [
    { id: 10001, name: 'Test1', role: 'Develop', sex: 'Man', age: 46, attr3: 22, attr4: 100, attr5: 66, attr6: 86, address: 'Guangzhou' },
    { id: 10002, name: 'Test2', role: 'Test', sex: 'Women', age: 0, attr3: 0, attr4: 0, attr5: 0, attr6: 0, address: 'Shenzheng' },
    { id: 10003, name: 'Test3', role: 'PM', sex: 'Man', age: 0, attr3: 22, attr4: 0, attr5: 0, attr6: 0, address: 'Shanghai' },
    { id: 10004, name: 'Test4', role: 'Designer', sex: 'Women', age: 0, attr3: 0, attr4: 0, attr5: 0, attr6: 0, address: 'Guangzhou' },
    { id: 10005, name: 'Test5', role: 'Test', sex: 'Women', age: 0, attr3: 0, attr4: 0, attr5: 0, attr6: 0, address: 'Shenzheng' },
    { id: 10006, name: 'Test6', role: 'Develop', sex: 'Man', age: 0, attr3: 0, attr4: 0, attr5: 0, attr6: 0, address: 'Guangzhou' },
    { id: 10007, name: 'Test7', role: 'Designer', sex: 'Women', age: 0, attr3: 0, attr4: 0, attr5: 0, attr6: 0, address: 'Guangzhou' },
    { id: 10008, name: 'Test8', role: 'Test', sex: 'Man', age: 0, attr3: 0, attr4: 0, attr5: 0, attr6: 0, address: 'Guangzhou' }
  ]
})

const setMerge1 = () => {
  gridOptions.mergeHeaderCells = [
    { row: 0, col: 0, rowspan: 2, colspan: 1 },
    { row: 0, col: 1, rowspan: 2, colspan: 1 },
    { row: 0, col: 2, rowspan: 1, colspan: 2 },
    { row: 0, col: 4, rowspan: 1, colspan: 2 },
    { row: 1, col: 6, rowspan: 1, colspan: 2 },
    { row: 0, col: 8, rowspan: 2, colspan: 1 }
  ]
}

const setMerge2 = () => {
  gridOptions.mergeHeaderCells = [
    { row: 0, col: 0, rowspan: 2, colspan: 1 },
    { row: 0, col: 1, rowspan: 2, colspan: 1 },
    { row: 0, col: 2, rowspan: 1, colspan: 4 },
    { row: 1, col: 6, rowspan: 1, colspan: 3 }
  ]
}

const saveMergeData = () => {
  const $grid = gridRef.value
  if ($grid) {
    const mergeList = $grid.getMergeHeaderCells()
    console.log(mergeList)
  }
}
</script>

image

注意

注意事项 说明
列宽调整限制 被合并的列(即参与 colspan 的列)将无法通过拖拽调整列宽。如果需要调整列宽,请在未合并的列上进行,或通过代码动态设置列宽。
合并规则与列索引对应 mergeHeaderCells 中的 col 索引指的是 columns 数组的索引(从0开始)。当有 type: 'seq' 或 type: 'checkbox' 等内置列时,这些列也占用一个索引位置。
行索引规则 合并的行索引 row 从0开始(第一行表头)。如果合并后表头最大行数为2,则有效行索引为0和1。超出范围会导致渲染异常。
必须保证所有基础列被覆盖 每一个叶子列(即实际绑定字段的列)在表头矩阵中都必须有对应的单元格,否则该列将没有表头文字。合并时可以通过 colspan 让多个列共享一个表头单元格。
动态切换合并规则 直接修改 mergeHeaderCells 会触发表头重新渲染,但不会影响已加载的数据。如果表格数据量大,频繁切换可能引起性能抖动,建议使用防抖或仅在必要时切换。
与列固定(fixed)的兼容 如果某些列设置了 fixed(左右固定),合并规则需要小心处理,避免将固定列与非固定列合并,否则可能导致样式错乱。
  • vxe-table 的 showCustomHeader 和 mergeHeaderCells 提供了一种高度自由的自定义表头合并方案,适用于需要复杂表头布局的报表、数据展示等场景。主要优势包括:
    • 完全自定义:不受内置树形分组限制,可以实现任意行列合并。
    • 动态可切换:通过修改 mergeHeaderCells 即可实时改变表头结构。
    • 与数据解耦:合并只影响表头展示,不影响数据行的渲染和绑定。

https://vxetable.cn

posted @ 2026-06-09 10:47  独行者r2  阅读(7)  评论(0)    收藏  举报