一、背景
在现代项目开发中,众所周知,对于excel的文件一般由后端开发人员做下载导出链接,进行导出功能的实现。而最近我在工作中遇到了这样的问题,就是表格的数据统计依赖总公司的综合数据,且数据类目庞大,因此后端查询接口在尽力优化下,每个接口也将近30s的反应时间,这对于用户来说是不友好的。而且页面呈现的数据报表已经等待了几十秒加载出来,如果在导出的时候还需要在进行等待重新访问接口,势必是对用户体验不太好。所以我决定通过前端来导出这些已经拿到的table数据。这样就可以节省二次访问时间啦~
二、依赖及解决的问题
依赖:element-ui-table + file-saver + xlsx
在项目中因为考虑到快速开发迭代的节奏,我们选用了Element-UI的Table组件。但是在导出excel的同时,也遇到了一些棘手的问题。
三、解决的问题
- 因为table组件中用到了fixed的属性,在过长的表格,用于对核心的数据列或数据表头进行固定。但是因为fixed的属性,在进行导出的时候会导出两个table。因为我们探究一下就可以发现,当table组件使用了fixed的属性时,对于固定单元和非固定单元是进行了不同table的拼接,因此我们在进行excel导出的时候要进行处理。
具体的处理方法是:在要导出时,先保存fixed的固定dom节点,然后删除它,进行数据导出以后,在进行append就好啦。 - 第二个问题是:在导出excel的时候,我们都知道,有sheet的分类,正常情况下是默认一个sheet的。但是如何在一个excel中导出含有多个sheet的文件呢。
具体的处理方法是:这个时候就要用到XLSX.utils.table_to_sheet()
这个方法进行多sheet的拼接。 - 第三个问题是:导出的excel中如果是百分比的数据,导出的格式就是字符串形式,但是excel会有黄色的警告。其实对于这个问题也有解决。
具体的处理方法是:就是通过声明let xlsxParam = { raw: true } // 导出的内容只做解析,不进行格式转换
。但是导出的时候确实数字了,不过就没有百分比的形式啦。举例:'80%' => 0.8 因此,这里我建议大家还是只做解析,不进行格式转换。 - 第四个问题就是对于excel的导出的兼容性和速度的取舍,涉及到这样一个属性
bookSST: true
。当bookSST为false就相应的降低了兼容性,但同时也提高了导出生成表格的速度。这里我考虑的是兼容性,因此我设置为true了。
/*
* @Author: xuhao
* @Date: 2020-05-28 17:02:39
* @description: Table数据导出为excel文件,该导出为前端导出,依赖现有数据,少一次请求(部分请求最高达30s),节省用户等待时间。
* @Last Modified by: xuhao
* @Last Modified time: 2020-07-09 11:24:42
*/
//引入依赖
import FileSaver from 'file-saver';
import XLSX from 'xlsx';
// id为table的标示,title为table名称
export const exportExcel = (id, title) => {
let ids, wbout;
// 判断是否是含多sheet的excel
if (id.includes(',')) { // 含多sheet的excel
ids = JSON.parse(id)
let workbook = XLSX.utils.book_new();
let xlsxParam = { raw: true } // 导出的内容只做解析,不进行格式转换
ids.forEach((item, index) => {
let tableDom = document.querySelector(`#${item.key}`)
let fix = document.querySelector(`#${item.key} .el-table__fixed`);
if (fix) { // 如果存在固定列,防止导出的excel表格会重复两遍
// workbook = XLSX.utils.table_to_sheet(dom, xlsxParam);
XLSX.utils.book_append_sheet(workbook, XLSX.utils.table_to_sheet(tableDom.removeChild(fix), xlsxParam), item.name);
tableDom.appendChild(fix)
} else {
XLSX.utils.book_append_sheet(workbook, XLSX.utils.table_to_sheet(document.querySelector(`#${item.key}`), xlsxParam), item.name);
}
})
// bookSST 开启之后会降低导出速率,但是会提高兼容性
wbout = XLSX.write(workbook, { bookType: 'xlsx', bookSST: true, type: 'array' });
} else { // 单个默认sheet的excel
ids = id
/* generate workbook object from table */
// 判断要导出的节点中是否有fixed属性(即,固定列)的表格,如果有,转换excel时先将该dom移除,然后append回去
let fix = document.querySelector(`#${ids} .el-table__fixed`);
let workbook;
let xlsxParam = { raw: true } // 导出的内容只做解析,不进行格式转换
if (fix) { // 如果存在固定列,防止导出的excel表格会重复两遍
let dom = document.querySelector(`#${ids}`).removeChild(fix)
workbook = XLSX.utils.table_to_book(dom, xlsxParam)
document.querySelector(`#${ids}`).appendChild(fix)
} else {
workbook = XLSX.utils.table_to_book(document.querySelector(`#${ids}`), xlsxParam);
}
// bookSST 开启之后会降低导出速率,但是会提高兼容性
wbout = XLSX.write(workbook, { bookType: 'xlsx', bookSST: true, type: 'array' });
}
/* get binary string as output */
try {
FileSaver.saveAs(new Blob([wbout], { type: 'application/octet-stream' }), title)
} catch (e) {
if (typeof console !== 'undefined') {
console.log(e, wbout)
}
}
return wbout
};
Comments | NOTHING