基于antd的table表格excel简单导出实践
本文主要内容:
1.介绍antd的table的基本属性
2.结合antd导出xlsx
3.介绍主要的特点:合并操作,多sheet导出
4.结合官网的例子进行演示
食用前提:对antd,react有一定的基础。
业务背景:
antd的table表格展示比较方便,只要配置了相关的列属性和数据,就可以展示比较友好的前端页面表格了。如果我们想要基于table的数据显示导出antd表格的数据,怎么办?
本文主要是基于antd的table表格实现前端excel导出的简单实践,使用antd的table的dataSource和columns配置即可,实现了单元格合并和导出多个sheet。
1.介绍antd的table的基本属性
antd中table组件的属性介绍在antd官网有详细的介绍。这里主要介绍本文用到的属性。
- column.title:列头显示文字。
- column.dataIndex:列数据在数据项中对应的路径,这里用的是string类型,故解释为对应的对象名更合适。
- column.width:列宽度。
- column.colSpan:表头合并单元格数。
- column.render:(重点)生成复杂数据的渲染函数,参数为当前行的值,当前行数据,和当前行索引。render可以返回一个字符串value,或者一个jsx对象,或者一个对象等,本文主要用到如下的render对象。
{
children:value,
props:{
rowSpan:1, // 跨行数
colSpan:1 // 跨列数
}
}
- table.dataSource:数据数组,即每一行的数据项。
2.结合antd导出xlsx
这里用到的导出excel的库是js-xlsx,很方便的就将json数据导出为Excel文件。
导出的流程为:
1.新建工作簿(workBook);
2. 新建一个工作表(Sheets);
3. 构建数据项对象数组,由于antd中table的dataSource本身就是一个数据项对象数组,可以使用json转sheet函数,故这里直接使用dataSource和columns配置构建出json对象数据即可。
4.基本样式处理:主要设置列宽和合并操作;
5.工作薄添加sheet;
6.导出excel表格。
0.引入xlsx库
import XLSX from 'xlsx';
1.新建一个工作薄
var wb = XLSX.utils.book_new();
2.新建一个工作表&构建数据项对象数组
每一个单元格是一个对象,主要含有v,s,t等字段,v是原始值,s是表格样式,t是内容类型。这里主要使用v字段,默认是字符串类型。
以下data是数据项数组,columns是列属性配置数组。
let table = new Array();
data.forEach((item: any, i: number) => {
let row: DerictoryObj<any> = {};
columns.forEach((el: any) => {
if (el.render) {
if (typeof el.render === 'function') {
const render = el.render(item[el.dataIndex], item, i);
row[el.title] = {
v: render ? (render.children ? render.children : render) : '',
};
} else {
const render = el.render(item[el.dataIndex], item, i);
row[el.title] = { v: render || '' };
}
} else {
row[el.title] = { v: item[el.dataIndex] };
}
});
table.push(row);
});
//json转sheet
var ws = XLSX.utils.json_to_sheet(table);
这里使用json_to_sheet函数将json数据转化为sheet,该函数接受处理好的json对象作为参数。
比较重要的一点是,如果column项含有render函数,说明数据需要进一步处理。所以判断column存在render,且render是函数,即调用render函数返回最终的结果。对于jsx对象,本文不做兼容处理。
3.设置列属性
//设置列宽
ws['!cols'] = columns.map((item: any) => {
if (item.width) {
return { width: item.width / 5 };
} else {
return { width: 20 };
}
});
4.工作簿添加sheet
//sheet写入book
XLSX.utils.book_append_sheet(wb, ws, sheetName); // wb:工作簿,ws:工作表,sheetName:工作表名
5.导出excel
// 导出数据
XLSX.writeFile(wb, fileName + '.xlsx');
3.介绍主要的操作:合并操作,多sheet导出
(1)合并操作:
合并操作,需要用到的是ws中的 '!merges' 对象。分别需要处理列表头的合并和数据单元的合并。列表头的合并只处理列合并,数据单元的合并处理列合并和行合并。
合并属性介绍:
ws['!merges'] = [{
s:{ // s为开始的单元格
r:1, // r为行数,从0开始
c:2 // c为列数,从0开始
},
e:{ // e为结束的单元格
r:2,
c:2
}
}]
- 列表头的合并:
// 表格表头合并设置
const headerMerges = columns && columns.reduce((t: any, el: any, c: number) => {
const { colSpan } = el;
if (colSpan && colSpan > 0) {
return [
...t,
{
s: { r: 0, c: c },
e: { r: 0, c: c + colSpan - 1 }
},
]
}
return t;
}, [])
- 数据单元合并:
const dataMerges =
data &&
data.length > 0 &&
data.reduce((total: any, item: any, r: number) => {
return [
...total,
...columns.reduce((t: any, el: any, c: number) => {
const span = el.render && el.render(item[el.dataIndex], item, r)?.props;
let colSpan, rowSpan;
if (span) {
colSpan = span?.colSpan;
rowSpan = span?.rowSpan;
}
if ((rowSpan && rowSpan > 1) || (colSpan && colSpan > 1)) {
return [
...t,
{
s: { r: r + 1, c: c },
e: { r: rowSpan ? (r + rowSpan) : (r + 1), c: colSpan ? c + colSpan - 1 : c }
},
];
}
return t;
}, []),
];
}, []);
由于数据单元的的合并属性rowSpan和colSpan属性是通过render属性获得的,所以需要遍历data和colums的进行属性合并扫描。
- 合并列合并和数据单元格合并:
ws['!merges'] = [...headerMerges, ...dataMerges];
(2)工作簿中添加多个sheet:
XLSX.utils.book_append_sheet(wb, ws, sheetName);
wb为工作薄,ws为工作表,sheetName为工作表的名称,可以多次插入工作表。
4.实例演示
以antd的官网例子为例:
实现导出这个表格的excel,当然这里进行了一些处理,本文代码不支持jsx。
结果截图如下: