antd Table 组件动态合并单元格

最近处理table的时候 遇到了要合并同一列的几行的情况,比如第一列的前面三行都是同一个对象的名字,此时合并显示比较妥当,但是数据是后端接口来的,而且可以筛选条件,搜索出来的数据就是动态的长度,可能这次需要合并前面的五行, 在原有的静态数据的合并的基础上,需要加上一个合并的逻辑代码

请添加图片描述

下面的内容使用 "antd": "^5.7.0", 其他可能方法名略有不同

下面分两步讲解:

1、静态数据表格的行合并,讲解Table组件如何使用rowSpan进行合并

2、动态数据表格的行合并,通过在静态的处理之上加入解析逻辑来实现

本质是对数据源的处理,提前算好需要合并的数量存储到每一行的数据中去,渲染的时候直接通过合并属性赋值即可,这里只是讲解了行的合并,列的合并也是同样的思路

1、静态表格合并行

实现思路:处理columns中的rowSpan,遇到需要合并的行,设置rowSpan的数量为需要合并的行总数,然后把后面的rowSpan设置为0(不渲染该位置),否则这个表格就会乱套

下面就是我们合并了 ‘分类’ 列下面的 【1,2】行 ,【4,5,6】 行

import React, { useEffect, useState } from 'react'
import { Table} from 'antd'

export default function Index() {
  const [ tableData, setTableData ] = useState<any>([])

  const columns = [
    {
      title: '分类',
      dataIndex: 'category',
      onCell: (row, index) => {
        // 合并 【1,2】行
        if (index === 0) {
          return { rowSpan: 2 }
        }
        if (index === 1) {
          return { rowSpan: 0 }
        }
        // 合并【4,5,6】 行
        if (index === 3) {
          return { rowSpan: 3 }
        }
        if (index === 4) {
          return { rowSpan: 0 }
        }
        if (index === 5) {
          return { rowSpan: 0 }
        }
      }
    },
    {
        title: '名称',
        dataIndex: 'name',
    },
    {
        title: '评价',
        dataIndex: 'desc',
    },
  ];

  useEffect(() => {
    // 模拟生命周期接口获取数据
    let data = [
      {
        "category":"水果",
        "name": "桃",  
        "desc": "桃子好吃"
      },{
        "category":"水果",
        "name": "梨",  
        "desc": "梨子真好吃"
      },{
        "category":"蔬菜",
        "name": "茄子",  
        "desc": "茄子茄子"
      },{
        "category":"家禽",
        "name": "牛肉",  
        "desc": "吃不起"
      },{
        "category":"家禽",
        "name": "羊肉",  
        "desc": "羊肉好羊肉"
      },{
        "category":"家禽",
        "name": "猪肉",  
        "desc": "good"
      }
    ]
    setTableData(data)
  }, [])


  return (
    <Table
      bordered
      rowKey="name"
      columns={columns}
      dataSource={tableData}
      pagination={false}
    />
  )
}

2、动态表格合并行

根本的原理:处理数据源,合并行列的操作的数量都会在数据源中,提前算好渲染的rowSpan到每一行中就可以

主要看 handleData 函数,作一次循环找到重复类型的第一个row, 并向后一个比较,直到遍历完毕数组:

  1. 设置 startItem 记录开始计数的对象,并默认rowSpan = 1(自己就是1个)

  2. 取下一项进行比较,当 dataIndex (这里是类名) 相同则记录 startItem.rowSpan + 1 , 否则说明已经没有更多dataIndex重复的项了,设置新的startItem为下一项重复以上步骤,直到遍历结束

import React, { useEffect, useState } from 'react'
import { Table} from 'antd'

export default function Index() {
  const [ tableData, setTableData ] = useState<any>([])

  const columns = [
    {
        title: '分类',
        dataIndex: 'category',
        onCell: (row:any) => ({ rowSpan: row.rowSpan || 0 })
    },
    {
        title: '名称',
        dataIndex: 'name',
    },
    {
        title: '评价',
        dataIndex: 'desc',
    },
  ];

  useEffect(() => {
    // 模拟生命周期接口获取数据、处理数据
    let data = [
      {
        "category":"水果",
        "name": "桃",  
        "desc": "桃子好吃"
      },{
        "category":"水果",
        "name": "梨",  
        "desc": "梨子真好吃"
      },{
        "category":"蔬菜",
        "name": "茄子",  
        "desc": "茄子茄子"
      },{
        "category":"家禽",
        "name": "牛肉",  
        "desc": "吃不起"
      },{
        "category":"家禽",
        "name": "羊肉",  
        "desc": "羊肉好羊肉"
      },{
        "category":"家禽",
        "name": "猪肉",  
        "desc": "good"
      }
    ]
    let res = handleData(data, 'category')
    setTableData(res)
  }, [])

  // 处理数据rowSpan函数
  const handleData = (array, key) => {
    if(array.length === 0) return
    let arr = [...array]
    // 1、startItem(默认rowSpan = 1)记录开始计数的对象
    let startItem:any = arr[0]
    startItem.rowSpan = 1
    // 2、遍历数组,取下一项进行比较,当name相同则startItem的rowSpan+1, 否则设置新的startItem为下一项
    arr.forEach((item:any, index) => {
      let nextItem:any = arr[index+1] || {}
      if(item[key] === nextItem[key]){
        startItem.rowSpan++
      }else{
        startItem = nextItem
        startItem.rowSpan = 1
      }
    })
    return arr
  }

  return (
    <Table
      bordered
      rowKey="name"
      columns={columns}
      dataSource={tableData}
      pagination={false}
    />
  )
}

以上都是基础用法,可以给这个函数改写一下,适应更复杂的场景

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐