react结合antd的Table组件实现动态单元格合并

首先看一下antd的Table表单组件,合并单元格,用到了rowSpan(合并行)和colSpan(合并列)

 后台返回的数据

[
    {
      key: 0,
      category: '水果',
      name: '桃子',
      desc: '好吃',
    },
    {
      key: 1,
      category: '水果',
      name: '梨子',
      desc: '真好吃',
    },
    {
      key: 2,
      category: '蔬菜',
      name: '茄子',
      desc: '真好吃',
    },
    {
      key: 9,
      category: '蔬菜',
      name: '茄子',
      desc: '真好吃',
    },
    {
      key: 3,
      category: '家禽',
      name: '牛肉',
      desc: '太好吃了',
    },
    {
      key: 4,
      category: '家禽',
      name: '羊肉',
      desc: '真不错',
    },
    {
      key: 5,
      category: '家禽',
      name: '猪肉',
      desc: '吃不起,太贵',
    },
    {
      key: 4,
      category: '家禽',
      name: '羊肉',
      desc: '真不错',
    },
    {
      key: 5,
      category: '家禽',
      name: '猪肉',
      desc: '吃不起,太贵',
    },
  ]

我们希望把category的值相同的,行合并成一个单元格

类似于这种

 rowSpan这个属性可以指定合并行。例如说第一行,指定rowSpan为3,意思就是合并三行,则后面紧挨的两行的rowSpan就需要设置为0。因为他们一共就占有3份,第一行的为3份,已经占完了,下面俩就不能再占了,就必须为0

官网实例中,使用onCell属性,来指定合并多少行/列,onCell的值是一个函数,默认接收2个参数,第一个参数是当前行数据,第二个参数就是这行的索引

我在网上看了一些大佬的做法,感觉直接处理源数据,在源数据中添加它这个所占的份数,直接通过在onCell中指定他所需要合并的行的个数,这种做法最简单

也就是把源数据处理成这种 

[
    {
      key: 0,
      category: '水果',
      name: '桃子',
      desc: '好吃',
      rowSpan: 2,
    },
    {
      key: 1,
      category: '水果',
      name: '梨子',
      desc: '真好吃',
      rowSpan: 0,
    },
    {
      key: 2,
      category: '蔬菜',
      name: '茄子',
      desc: '真好吃',
      rowSpan: 2,
    },
    {
      key: 9,
      category: '蔬菜',
      name: '茄子',
      desc: '真好吃',
      rowSpan: 0,
    },
    {
      key: 3,
      category: '家禽',
      name: '牛肉',
      desc: '太好吃了',
      rowSpan: 3,
    },
    {
      key: 4,
      category: '家禽',
      name: '羊肉',
      desc: '真不错',
      rowSpan: 0,
    },
    {
      key: 5,
      category: '家禽',
      name: '猪肉',
      desc: '吃不起,太贵',
      rowSpan: 0,
    },
    {
      key: 4,
      category: '家禽',
      name: '羊肉',
      desc: '真不错',
      rowSpan: 0,
    },
    {
      key: 5,
      category: '家禽',
      name: '猪肉',
      desc: '吃不起,太贵',
      rowSpan: 0,
    },
  ]

具体代码如下

import { Table } from 'antd'

const Demo1 = () => {
  let field = 'category'
  const data = [
    {
      key: 0,
      category: '水果',
      name: '桃子',
      desc: '好吃',
      // rowSpan: 2,
    },
    {
      key: 1,
      category: '水果',
      name: '梨子',
      desc: '真好吃',
      // rowSpan: 0,
    },
    {
      key: 2,
      category: '蔬菜',
      name: '茄子',
      desc: '真好吃',
      // rowSpan: 2,
    },
    {
      key: 9,
      category: '蔬菜',
      name: '茄子',
      desc: '真好吃',
      // rowSpan: 0,
    },
    {
      key: 3,
      category: '家禽',
      name: '牛肉',
      desc: '太好吃了',
      // rowSpan: 3,
    },
    {
      key: 4,
      category: '家禽',
      name: '羊肉',
      desc: '真不错',
      // rowSpan: 0,
    },
    {
      key: 5,
      category: '家禽',
      name: '猪肉',
      desc: '吃不起,太贵',
      // rowSpan: 0,
    },
    {
      key: 4,
      category: '家禽',
      name: '羊肉',
      desc: '真不错',
      // rowSpan: 0,
    },
    {
      key: 5,
      category: '家禽',
      name: '猪肉',
      desc: '吃不起,太贵',
      // rowSpan: 0,
    },
  ]
  const columns = [
    {
      title: '姓名',
      dataIndex: 'category',
      onCell: (record, index) => {
        // console.log(record.category, record.rowSpan)
        return { rowSpan: record.rowSpan }
      },
    },
    {
      title: '床位',
      // colSpan: 2, // 设置占位2格
      dataIndex: 'parentType',
      /**
       * 每4行都是一个日期,从index = 0 开始,
       * 每隔4行的rowSpan为4,其余的rowSpan为0
       */
      // onCell: (_, index) => ({
      //   rowSpan: index % 2 === 0 || index === 0 ? 2 : 0,
      // }),
    },
    {
      title: '组',
      // colSpan: 0, // 设置占位0格
      dataIndex: 'type',
    },
    {
      title: '药房',
      dataIndex: 'user1',
    },
    {
      title: '类型',
      dataIndex: 'user2',
    },
    {
      title: '项目名称',
      dataIndex: 'user3',
    },
    {
      title: '规格',
      dataIndex: 'user4',
    },
  ]
  const changeData = (data, field) => {
    let count = 0 //重复项的第一项
    let indexCount = 1 //下一项
    while (indexCount < data.length) {
      var item = data.slice(count, count + 1)[0] //获取没有比较的第一个对象
      if (!item.rowSpan) {
        item.rowSpan = 1 //初始化为1
      }
      if (item[field] === data[indexCount][field]) {
        //第一个对象与后面的对象相比,有相同项就累加,并且后面相同项设置为0
        item.rowSpan++
        data[indexCount].rowSpan = 0
      } else {
        count = indexCount
      }
      indexCount++
    }
  }
  changeData(data, field) //处理数据

  return (
    <div>
      <Table
        columns={columns}
        dataSource={data}
        pagination={false}
        bordered
      ></Table>
    </div>
  )
}

export default Demo1

React表格中的列合并功能通常用于展示数据时,当遇到相同值时将它们合并在一起显示,以便减少重复并提高可读性。这通常通过JavaScript库如`react-table`或自定义组件实现。在`react-table`中,你可以使用`Aggregation`或`Pagination极度`配合`useTable` hook来处理这种情况。以下是基本步骤: 1. 首先,安装`react-table`和`ag-grid`等库(如果需要): ```sh npm install react-table ag-grid --save ``` 2. 然后,在组件中设置表头和行数据处理: ```jsx import { useTable, Column } from 'react-table'; import { AggregatedRow } from 'react-table-aggregations'; function MyTable({ data }) { const columns = [ // 添加一个聚合列 { Header: '姓名', accessor: 'name', // 数据字段名 Cell: (row) => row.values.name, // 显示每个值 Footer: ({ get aggregation }) => { return aggregation?.name; // 根据合并后的结果返回 }, Aggregation: ({ column: { id }, table }) => { const values = table.rows.map((row) => row.values[id]); return { name: [...new Set(values)], // 获取唯一值并转换为数组 count: values.length, // 合并值的数量 }; }, }, ]; const table = useTable({ data, columns, }); return ( <table> {/* 使用AggregatedRow替代普通行 */} {table.getHeaderGroups().map((headerGroup) => ( <tr key={headerGroup.id}> {headerGroup.headers.map((column) => ( <th {...column.getHeaderProps()}>{column.render('Header')}</th> ))} </tr> ))} {table.getRowGroupBy('name').map((group) => ( <AggregatedRow {...group} key={group.key}> {group.cells.map((cell) => cell.render('Cell'))} </AggregatedRow> ))} </table> ); } ```
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值