You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现多rowSpan合并单元格表格的层级数据适配渲染

多级rowSpan合并层级表格通用实现方案

问题背景

开发带多级行合并的层级数据表格时,已完成基础表格框架搭建,但处理三层嵌套的原始数据时,仅能通过map逐层遍历、硬编码rowSpan值实现固定数据渲染,无法适配动态数据,需要通用的数据规整方案,将嵌套数据转换为可直接驱动表格渲染的结构。

原始数据结构

const CHOICE_CHECKUP_MOCK = [
  {
    category_name: "ChoiceA",
    possible_count: 1,
    checkup_list: [
      {
        middle_checkup_name: "ChoiceA middle list1",
        checkups: [
          {
            name: "SubClass 1-1",
            code: "code 1-1",
            description: "description 1-1",
            price: 0,
          },
          {
            name: "subClass 1-2",
            code: "code 1-2",
            description: "description 1-2",
            price: 0,
          },
        ],
      },
      {
        middle_checkup_name: "ChoiceA middle list2",
        checkups: [
          {
            name: "checkups_name3",
            code: "checkups_code3",
            description: "checkups_description3",
            price: 0,
          },
          {
            name: "checkups_name4",
            code: "checkups_code4",
            description: "checkups_description4",
            price: 0,
          },
        ],
      },
    ],
  },
  {
    category_name: "ChoiceB",
    possible_count: 1,
    checkup_list: [
      {
        middle_checkup_name: "ChoiceB middleClassList1",
        checkups: [
          {
            name: "SubClass 1-1",
            code: "code 1-1",
            description: "description 1-1",
            price: 0,
          },
          {
            name: "subClass 1-2",
            code: "code 1-2",
            description: "description1-2",
            price: 0,
          },
          {
            name: "subClass 1-2",
            code: "code 1-2",
            description: "description 1-2",
            price: 0,
          },
        ],
      },
      {
        middle_checkup_name: "ChoiceB MiddleClassList2",
        checkups: [
          {
            name: "checkups_name3",
            code: "checkups_code3",
            description: "checkups_description3",
            price: 0,
          },
          {
            name: "checkups_name4",
            code: "checkups_code4",
            description: "checkups_description4",
            price: 0,
          },
        ],
      },
    ],
  },
]

目标渲染效果

多级行合并层级表格效果

实现思路

核心是把三层嵌套数据拍平成一维行数组,拍平过程中自动计算每一层级的rowSpan,标记哪些行不需要渲染上层列的单元格,从根源上避免硬编码。

  • 第一步:提前计算各层级合并行数
    最内层checkups数组的长度,就是所属中间分类列的rowSpan值;每个一级分类下所有中间分类的checkups长度累加,就是一级分类列的rowSpan值。
  • 第二步:嵌套遍历拍平数据
    从最外层分类开始逐层向内遍历,每一条最内层的checkup明细对应表格的一行,给每行数据挂载三类字段:
    • 一级分类字段:仅当前行是该分类下的第一行时,携带分类名称、可选次数、rowSpan值,其余行该字段置为null,标记为不渲染该列
    • 中间分类字段:仅当前行是该中间分类下的第一行时,携带中间分类名称、rowSpan值,其余行该字段置为null,标记为不渲染该列
    • 明细字段:每一行都携带检查项的名称、编码、描述、价格信息
  • 第三步:按行渲染
    遍历拍平后的一维数组生成tr标签,每个tr内判断对应列的字段:有值就渲染td并绑定rowSpan属性,值为null就直接跳过该列td的生成即可。

核心代码实现

数据转换函数

function flattenTableData(rawList) {
  const rowList = []
  // 遍历一级分类
  rawList.forEach(category => {
    // 计算一级分类总占行数
    const categorySpan = category.checkup_list.reduce(
      (total, middleItem) => total + middleItem.checkups.length, 0
    )
    let isCategoryFirstRow = true

    // 遍历二级中间分类
    category.checkup_list.forEach(middleItem => {
      const middleSpan = middleItem.checkups.length
      let isMiddleFirstRow = true

      // 遍历三级明细,每个明细生成一行
      middleItem.checkups.forEach(checkupDetail => {
        rowList.push({
          categoryCell: isCategoryFirstRow ? {
            name: category.category_name,
            count: category.possible_count,
            rowSpan: categorySpan
          } : null,
          middleCell: isMiddleFirstRow ? {
            name: middleItem.middle_checkup_name,
            rowSpan: middleSpan
          } : null,
          detailCell: checkupDetail
        })
        isCategoryFirstRow = false
        isMiddleFirstRow = false
      })
    })
  })
  return rowList
}

渲染逻辑示例(JSX语法)

<tbody>
  {flattenTableData(CHOICE_CHECKUP_MOCK).map((row, idx) => (
    <tr key={idx}>
      {/* 一级分类列:仅首行渲染 */}
      {row.categoryCell && (
        <td rowSpan={row.categoryCell.rowSpan}>
          <p>{row.categoryCell.name}</p>
          <p>可选次数:{row.categoryCell.count}</p>
        </td>
      )}
      {/* 中间分类列:仅首行渲染 */}
      {row.middleCell && (
        <td rowSpan={row.middleCell.rowSpan}>{row.middleCell.name}</td>
      )}
      {/* 明细列:每行渲染 */}
      <td>{row.detailCell.name}</td>
      <td>{row.detailCell.code}</td>
      <td>{row.detailCell.description}</td>
      <td>{row.detailCell.price}</td>
    </tr>
  ))}
</tbody>

这个方案没有硬编码行数,不管嵌套数据里各层级有多少条子项,都能自动计算合并行数,新增、删减数据都不需要改渲染逻辑。如果后续要加更多层级的合并,只要按照同样的逻辑,在拍平时加对应层级的rowSpan计算和首行标记即可。


内容的提问来源于stack exchange,提问作者GaramSong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 06:00:58