使用 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>
效果展示
总结
使用自定义渲染函数,结合数据可以实现单元格合并功能。