antd Table 组件动态合并单元格

电玩女神 2022-12-02 00:26 1052阅读 0赞

antd Table 组件动态合并单元格

      • 前言
      • Table 组件静态数据合并单元格
      • 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 = [

    1. {
    2. title: '分类',
    3. dataIndex: 'category',
    4. render: (value, row, index) => {
    5. const obj = {
    6. children: value,
    7. props: { },
    8. };
    9. if (index === 0) {
    10. obj.props.rowSpan = 2;
    11. }
    12. if (index === 1) {
    13. obj.props.rowSpan = 0;
    14. }
    15. //没有相同项时可以不用设置 colSpan
    16. if (index === 2) {
    17. obj.props.rowSpan = 1;
    18. }
    19. if (index === 3) {
    20. obj.props.rowSpan = 3;
    21. }
    22. if (index === 4) {
    23. obj.props.rowSpan = 0;
    24. }
    25. if (index === 5) {
    26. obj.props.rowSpan = 0;
    27. }
    28. return obj;
    29. }
    30. },
    31. {
    32. title: '名称',
    33. dataIndex: 'name',
    34. },
    35. {
    36. title: '评价',
    37. dataIndex: 'desc',
    38. },

    ];

    const data = [
    {

    1. "category":"水果",
    2. "name": "桃子",
    3. "desc": "好吃"
    4. },{
    5. "category":"水果",
    6. "name": "梨子",
    7. "desc": "真好吃"
    8. },{
    9. "category":"蔬菜",
    10. "name": "茄子",
    11. "desc": "真TM好吃"
    12. },{
    13. "category":"家禽",
    14. "name": "牛肉",
    15. "desc": "太好吃了"
    16. },{
    17. "category":"家禽",
    18. "name": "羊肉",
    19. "desc": "好吃到停不下来"
    20. },{
    21. "category":"家禽",
    22. "name": "猪肉",
    23. "desc": "吃不起,太贵"
    24. }

    ]

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

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

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

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

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

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

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

  1. let data = [
  2. {
  3. "category":"水果",
  4. "name": "桃子",
  5. "desc": "好吃"
  6. },{
  7. "category":"水果",
  8. "name": "梨子",
  9. "desc": "真好吃"
  10. },{
  11. "category":"蔬菜",
  12. "name": "茄子",
  13. "desc": "真TM好吃"
  14. },{
  15. "category":"家禽",
  16. "name": "牛肉",
  17. "desc": "太好吃了"
  18. },{
  19. "category":"家禽",
  20. "name": "羊肉",
  21. "desc": "好吃到停不下来"
  22. },{
  23. "category":"家禽",
  24. "name": "猪肉",
  25. "desc": "吃不起,太贵"
  26. }
  27. ]

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

  1. data = [
  2. {
  3. "category":"水果",
  4. "name": "桃子",
  5. "desc": "好吃",
  6. "rowSpan":2
  7. },{
  8. "category":"水果",
  9. "name": "梨子",
  10. "desc": "真好吃",
  11. "rowSpan":0
  12. },{
  13. "category":"蔬菜",
  14. "name": "茄子",
  15. "desc": "真TM好吃",
  16. "rowSpan":1
  17. },{
  18. "category":"家禽",
  19. "name": "牛肉",
  20. "desc": "太好吃了",
  21. "rowSpan":3
  22. },{
  23. "category":"家禽",
  24. "name": "羊肉",
  25. "desc": "真不错",
  26. "rowSpan":0
  27. },{
  28. "category":"家禽",
  29. "name": "猪肉",
  30. "desc": "吃不起,太贵",
  31. "rowSpan":0
  32. }
  33. ]

算法题解思路:

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

代码:

  1. import dataJson from './data/Table.json';
  2. let data = dataJson.data;
  3. let field = 'category';
  4. const changeData = (data,field)=>{
  5. let count = 0;//重复项的第一项
  6. let indexCount = 1;//下一项
  7. while (indexCount<data.length){
  8. var item = data.slice(count,count+1)[0];//获取没有比较的第一个对象
  9. if(!item.rowSpan){
  10. item.rowSpan = 1;//初始化为1
  11. }
  12. if(item[field] === data[indexCount][field]){ //第一个对象与后面的对象相比,有相同项就累加,并且后面相同项设置为0
  13. item.rowSpan++;
  14. data[indexCount].rowSpan = 0;
  15. }else {
  16. count = indexCount;
  17. }
  18. indexCount++;
  19. }
  20. }
  21. changeData(data,field);//处理数据

总结

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

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

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

发表评论

表情:
评论列表 (有 0 条评论,1052人围观)

还没有评论,来说两句吧...

相关阅读