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 思想吗?所以程序设计思维真的很重要。

Ant Design Vue (Antd-Vue) 的表组件 Table 提供了一个自定义渲染功能 `customRender` 或 `render` 属性,用于动态合并单元,特别是当需要对数据和列进行动态处理的时候。`customRender`允许你完全控制每个单元的内容生成。 例如,如果你的数据结构包含嵌套的对象,或者某些列的值需要基于其他列计算得出,你可以编写一个函数接收当前行的数据、列配置以及索引等参数,然后返回一个 HTML 结构。以下是一个简单的示例: ```javascript <template> <a-table :data="tableData" :columns="tableColumns" :rowKey="getRowKey"> <template #cell="{ row, column, $index }"> <!-- 使用 customRender 进行动态合并 --> <span v-if="column.key === 'mergeColumn'" slot-scope="scope"> {{ customRender(row, column, scope.$index) }} </span> </template> </a-table> </template> <script> export default { data() { return { tableData: [ // ... 数据示例 ], tableColumns: [ { key: 'staticColumn', title: '静态列' }, { key: 'mergeColumn', title: '合并列', render: this.customRender }, // ... 其他列 ], }; }, methods: { getRowKey(item) { // 返回唯一标识,防止表重复渲染 return item.id; }, customRender(row, column, index) { // 根据实际需求编写合并逻辑 if (/* 判断条件 */) { // 可能会合并多个单元,这里可以拼接字符串或其他操作 return `${row.subData[index] || ''} ${row.anotherData[index]}`; } return row[column.key]; }, }, }; </script> ``` 在这个例子中,`customRender` 函数可以根据每行和每列的具体情况生成内容,并且由于支持列的动态设置,你还可以根据列配置决定是否合并及如何合并
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值