antd Table 组件动态合并单元格

前言

使用 antd 开发 PC端应用的人肯定知道的 Table 组件。一个功能很完善,界面很优化的表格组件。通过查阅官方文档,你可以很轻松地使用这个组件。但是如果表格中涉及到合并单元格昵?

文档中也有关于合并单元格的处理,但是只是静态数据的范例。而我们开发中往往都是获取的动态数据。那么Table 组件改如何动态合并单元格昵?

Table 组件静态数据合并单元格

这里简单地讲一下核心步骤,详细的步骤请直接移步官方文档。

在这里插入图片描述
以上是个简单的表格。现在我们将【分类】中相同的值合并,达到如下效果。

在这里插入图片描述
实现思路:

  1. 找到要合并列的第一列所在位置。记为 index。并且设置 rowSpan 为合并总列数。
    这里需要将 index 为 0 的 rowSpan 设置为 2。后面的相同项(也就是 index 为 1) 的 rowSpan 设置为 0。
  2. 同样地,需要将 index 为 2 的 rowSpan 设置为 1(没有相同项,就设置为1。也可以不用设置 rowSpan)。
  3. 最后,将 index 为 3 的 rowSpan 设置为 3,后面的相同项(也就是 index 为 4/5) 的 rowSpan 设置为 0。

const columns = [
    {
    
    
        title: '分类',
        dataIndex: 'category',
        render: (value, row, index) => {
    
    
	      const obj = {
    
    
	        children: value,
	        props: {
    
    },
	      };
	      if (index === 0) {
    
    
	        obj.props.rowSpan = 2;
	      }
	      if (index === 1) {
    
    
	        obj.props.rowSpan = 0;
	      }
	      //没有相同项时可以不用设置 colSpan 
	      if (index === 2) {
    
    
	        obj.props.rowSpan = 1;
	      }
	      if (index === 3) {
    
    
	        obj.props.rowSpan = 3;
	      }
	      if (index === 4) {
    
    
	        obj.props.rowSpan = 0;
	      }
	      if (index === 5) {
    
    
	        obj.props.rowSpan = 0;
	      }
	      return obj;
      }   
    },
    {
    
    
        title: '名称',
        dataIndex: 'name',
    },
    {
    
    
        title: '评价',
        dataIndex: 'desc',
    },
];

const data = [
  {
    
    
      "category":"水果",
      "name": "桃子",  
      "desc": "好吃"
    },{
    
    
      "category":"水果",
      "name": "梨子",  
      "desc": "真好吃"
    },{
    
    
      "category":"蔬菜",
      "name": "茄子",  
      "desc": "真TM好吃"
    },{
    
    
    "category":"家禽",
     "name": "牛肉",  
      "desc": "太好吃了"
    },{
    
    
    "category":"家禽",
     "name": "羊肉",  
      "desc": "好吃到停不下来"
    },{
    
    
    "category":"家禽",
     "name": "猪肉",  
      "desc": "吃不起,太贵"
    }
]

实现静态数据单元格合并总结一下就是两点。

  1. 设置合并列的第一列 rowSpan 为合并数。
  2. 设置其他相同项 rowSpan 为 0。

以上是处理静态数据,我们能够很快找到合并列的第一列以及合并数。但是如果是动态数据昵?我们不知道有几个【水果】,几个【蔬菜】和几个【肉类】。

Table 组件动态数据合并单元格

我最开始的想法是在 columns 对象的 render 中去完成这个功能。因为 render 中本来就是循环,暴露的参数又有限,所以很难去对比每个对象的相同项。后来经大牛指导可以先处理数据源。render 中直接使用带有逻辑的数据源就好了。

于是茅塞顿开,涉及到要处理数据逻辑,那么这个问题就转换成了一道算法题。

算法题:
假如在真实的开发场景中接口返回如下数据格式。

let data = [
  {
    
    
      "category":"水果",
      "name": "桃子",  
      "desc": "好吃"
    },{
    
    
      "category":"水果",
      "name": "梨子",  
      "desc": "真好吃"
    },{
    
    
      "category":"蔬菜",
      "name": "茄子",  
      "desc": "真TM好吃"
    },{
    
    
    "category":"家禽",
     "name": "牛肉",  
      "desc": "太好吃了"
    },{
    
    
    "category":"家禽",
     "name": "羊肉",  
      "desc": "好吃到停不下来"
    },{
    
    
    "category":"家禽",
     "name": "猪肉",  
      "desc": "吃不起,太贵"
    }
]

界面要求:将【分类】中相同值进行合并单元格。
经过上面对静态数据的逻辑处理,我们知道需要将每个相同项的第一项的 rowSpan 设置为合并数。并且其他的相同项设置为 0。得到后的数据格式如下:

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

算法题解思路:

  1. 定义 count 为重复项的第一项索引。
  2. 定义 indexCount 为下一项的索引。
  3. 取出数组第一个对象 item,先将 rowSpan 初始化为1。然后将 item 的【分类】值与下一项进行对比,发现一个相同项,rowSpan 就加1,并且下一项的 rowSpan 设置为 0。每对比一次,indexCount 累加。当没有遇到相同项时将 indexCount 赋值给 count。获取下一个相同项首项。
  4. 按照1/2/3的步骤,数组循环完之后就可以正确的赋值 rowSpan。

代码:

import dataJson from './data/Table.json';
let data = dataJson.data;
let field = 'category';
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);//处理数据

总结

总结就一句话:数据处理逻辑思维,MVC 和 MVP 思想

最开始做这个功能的时候,我一直沉浸在渲染页面 column 对象的 render 函数里去处理逻辑。但是 render 里面本来就是一个循环,参数有限,所以思维变得非常拘泥。

经大神点播可以先把数据源处理好再直接渲染页面,我才发应过来这种业务逻辑最好的处理方式就是直接处理数据状态,用数据状态代替业务逻辑。这不就是所谓的 MVC 和 MVP 思想吗?所以程序设计思维真的很重要。

猜你喜欢

转载自blog.csdn.net/weixin_44135121/article/details/108277720
今日推荐