使用 Ant Design Vue 自定渲染函数customRender实现单元格合并功能rowSpan

使用 Ant Design Vue 自定渲染函数customRender实现单元格合并功能rowSpan

背景

在使用Ant Design Vue 开发数据表格时,我们常常会遇到需要合并单元格的需求。

比如,某些字段的值可能会在多行中重复出现,而我们希望将这些重复的单元格合并为一个单元格。

通过自定义渲染函数和数据处理来实现 rowSpan 合并。

具有共同上级菜单的单元格进行合并展示

真实环境 具有相同上级菜单的单元格进行合并
请添加图片描述

模拟数据
请添加图片描述

环境准备

表格 Table - Ant Design Vue

首先,确保你已经安装了 Ant Design Vue。如果你还没有安装,可以通过以下命令安装:

npm install ant-design-vue --save

接下来,确保在你的 Vue 项目中正确引入 Ant Design Vue:

import { Table } from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';

表格结构及需求

这里我是用假数据模拟,假设我们有一个表格,需要展示以下数据:

const items = [
  { parentName: '父级菜单1', menuName: '菜单名称1', address: 'New York' },
  { parentName: '父级菜单1', menuName: '菜单名称2', address: 'Los Angeles' },
  { parentName: '父级菜单2', menuName: '菜单名称3', address: 'Chicago' },
  { parentName: '父级菜单2', menuName: '菜单名称4', address: 'San Francisco' },
  { parentName: '父级菜单3', menuName: '菜单名称5', address: 'Seattle' },
];

在这张表中,parentName 字段存在多个相同的值,我们希望对相同的 parentName 进行单元格合并操作。最终效果是:父级菜单1父级菜单2 的两行 parentName 将合并成一个单元格。

代码实现

数据处理:计算 rowSpan

为了实现合并单元格,我们需要根据相同字段的连续行数动态计算每个单元格的 rowSpan 属性。

我们将通过一个名为 processTableData 的函数来处理数据。

需要重新处理我们的源数据,将parentName相同的行rowSpan记录起来,同时将不需要展示的单元格rowSpan重置为0

表头只支持列合并,使用 column 里的 colSpan 进行设置。
表格支持行/列合并,使用 render 里的单元格属性 colSpan 或者 rowSpan 设值为 0 时,设置的表格不会渲染。

const processTableData = data => {
  let result = [];
  let i = 0;
  while (i < data.length) {
    const currentItem = data[i];
    let rowSpan = 1;//
    // 计算当前 parentName 后续相同的行数
    while (i + rowSpan < data.length && data[i + rowSpan].parentName === currentItem.parentName) {
      rowSpan++;
    }

    // 为当前项设置 rowSpan,记录相同的行数量,
    result.push({
      ...currentItem,
      rowSpan
    });

    // !!!重点!!!合并的行都需要保留,但是这些保留的单元不需要渲染,设置rowSpan为0
    for (let j = 1; j < rowSpan; j++) {
      result.push({
        ...data[i + j],
        rowSpan: 0 // 后续行不需要合并
      });
    }
    // 跳过已经合并的行,
    i += rowSpan;
  }

  return result;
};
表格列配置:自定义渲染

在 Ant Design Vue 的 Table 组件中,我们可以使用 customRender 来对某列的渲染进行自定义。我们将使用 rowSpan 来控制每个单元格的合并效果。

表头只支持列合并,使用 column 里的 colSpan 进行设置。
表格支持行/列合并,使用 render 里的单元格属性 colSpan 或者 rowSpan 设值为 0 时,设置的表格不会渲染。

customRender

可以和jsx进行类比,这个函数可以返回html元素结构

Function(text, record, index) {}|slot-scope

生成复杂数据的渲染函数,参数分别为当前行的,当前行数据,行索引,@return 里面可以设置表格行/列合并,可参考 表格 Table - Ant Design Vue 表格行/列合并

scopedSlots

使用 columns 时,可以通过该属性配置支持 slot-scope 的属性,如 scopedSlots: { customRender: 'XXX'}配合a-table组件插槽使用

const columns = [
  {
    title: '父级菜单',
    dataIndex: 'parentName',
    // 自定义渲染函数,和jsx类似
    customRender: (text, record) => {
      return {
        children: text,
        attrs: {
        // 当rowSpan的值为零时,不渲染单元格,为其它值时,进行跨行
          rowSpan: record.rowSpan;// 获取通过processTableData处理后的rowSpan值,注意这里小驼峰命名
        }
      };
    }
  },
  {
    title: '菜单名称',
    key: 'menuName',
    width: 220,
    dataIndex: 'menuName',
    align: 'left',
    // 插槽渲染
    scopedSlots: { customRender: 'beautiful' },
    ellipsis: true
  },
  
  {
    title: 'Address',
    dataIndex: 'address',
    // 插槽渲染
   	scopedSlots: { customRender: 'beautiful' },
  }
];
完整代码

经过上面的步骤,我们实现最终效果

最后,我们将处理过的数据传递给 Table 组件,并在模板中进行渲染。

<template>
  <a-table style="background-color: white" :bordered="true" :columns="columns" :dataSource="tableDataList" :rowKey="(record, index) => index">
    <template slot="beautiful" slot-scope="scope">
      {{ scope }}
    </template>
  </a-table>
</template>

<script>
export default {
  components: {},
  data() {
    const items = [
      { parentName: '父级菜单1', menuName: '菜单名称1', key: Math.random(), address: 'New York' },
      { parentName: '父级菜单1', menuName: '菜单名称2', key: Math.random(), address: 'Los Angeles' },
      { parentName: '父级菜单2', menuName: '菜单名称3', key: Math.random(), address: 'Chicago' },
      { parentName: '父级菜单2', menuName: '菜单名称4', key: Math.random(), address: 'San Francisco' },
      { parentName: '父级菜单3', menuName: '菜单名称5', key: Math.random(), address: 'Seattle' }
    ];

    const processedData = this.processTableData(items);

    return {
      tableDataList: processedData,
      columns: [
        {
          title: '父级菜单',
          dataIndex: 'parentName',
          // 自定义渲染函数,和jsx类似
          customRender: (text, record) => {
            return {
              children: text,
              attrs: {
                rowSpan: record.rowSpan // 获取通过processTableData处理后的rowSpan值,注意这里小驼峰命名
              }
            };
          }
        },
        {
          title: '菜单名称',
          key: 'menuName',
          width: 220,
          dataIndex: 'menuName',
          align: 'left',
          // 插槽渲染
          scopedSlots: { customRender: 'beautiful' },
          ellipsis: true
        },

        {
          title: 'Address',
          dataIndex: 'address',
          scopedSlots: { customRender: 'beautiful' }
        }
      ]
    };
  },
  methods: {
    processTableData(data) {
      let result = [];
      let i = 0;
      while (i < data.length) {
        const currentItem = data[i];
        let rowSpan = 1; //
        // 计算当前 parentName 后续相同的行数
        while (i + rowSpan < data.length && data[i + rowSpan].parentName === currentItem.parentName) {
          rowSpan++;
        }

        // 为当前项设置 rowSpan,记录相同的行数量,
        result.push({
          ...currentItem,
          rowSpan
        });

        // !!!重点!!!合并的行都需要保留,但是这些保留的单元不需要渲染,设置rowSpan为0
        for (let j = 1; j < rowSpan; j++) {
          result.push({
            ...data[i + j],
            rowSpan: 0 // 后续行不需要合并
          });
        }
        // 跳过已经合并的行,
        i += rowSpan;
      }

      return result;
    }
  }
};
</script>

效果展示

请添加图片描述

总结

使用自定义渲染函数,结合数据可以实现单元格合并功能。

上一篇:0基础跟德姆(dom)一起学AI 深度学习05-RNN循环神经网络


下一篇:Pr:音频过渡