1、情景描述
后端提供了数据,但是不提供导出excel的接口,那怎么办?前端也可以实现excel导出噢~
2、所需依赖及示例讲解
import * as XLSX2 from 'xlsx';
import XLSX from 'xlsx-style';
注:只需要以上俩依赖,但是需要打上补丁噢~因为这俩依赖源码有点bug,至少在我现在用的时候有bug,如果你运行后无问题,那就不需要打补丁噢
补丁:
1、/node_modules/xlsx-style/dist/cpexcel.js
错误源码:var cpt = require('./cpt' + 'able');
应修改为:var cpt = cptable;
2、/node_modules/xlsx-style/dist/ods.js
错误源码:return require('../' + 'xlsx').utils;
应修改为:return require('./' + 'xlsx').utils;
不知道如何打补丁的童鞋请参考我另一篇博客:
【patch-package】修改node_modules下的依赖包源码
示例:
下面变量名不懂的可以结合参考我的源码理解噢~
// props.headerDisplay: 导出excel头部
{
autoIndex: '序号',
originName: '视频文件',
}
// headProp: 导出excel头部属性名数组
['autoIndex', 'originName']
// exportData: 导出文件数据(入参)
[
{
autoIndex: 1,
originName: 'xxx'
},
{
autoIndex: 2,
originName: 'xxx'
}
]
// header (入参)
[
{
prop: 'autoIndex',
width: 150
},
{
prop: 'originName',
width: 150
}
]
结果截图:
3、源码
exportTransfer为导出excel的方法,俩参数我写在上面的示例里了,其余的代码基本上不用改,我都写了相关注释,你也可以根据你自己的需求进行相关更改
exportTransfer(exportData, header) {
nextTick(() => {
const newData = [props.headerDisplay, ...exportData] // 封装组合后的数据
const headProp = header.map(item => item.prop) // 头部属性数组
// 把json转为worksheet对象 后续用这种方法
const wb = XLSX2.utils.json_to_sheet(newData, { header: headProp, skipHeader: true })
// return
const widthList = header.map(item => item.width ? Number(item.width) : 150)
// 举例一共有14列(包括序号,不包括操作栏)
wb['!cols'] = [] // 先初始化列数组配置
for (let i = 0; i < 14; i++) {
wb['!cols'][i] = {
wpx: widthList[i]
}
}
// 样式的文档地址
// https://www.npmjs.com/package/xlsx-style
for (const key in wb) {
if (key.indexOf('!') === -1) { // 非excel配置类,带!都是配置类,这里对非配置类进行样式修改
wb[key].s = {
font: { // 字体设置
sz: 13,
bold: false,
color: { // 只有DEFG第一行(标题行)才是红色,其余皆是黑色
rgb: new RegExp(/^[DEFG]1{1}$/).test(key) ? 'D9001B' : '000000'
}
},
alignment: { // 文字居中
horizontal: 'center',
vertical: 'center',
wrapText: 1 // 换行
},
border: { // 设置边框
top: { style: 'thin' },
bottom: { style: 'thin' },
left: { style: 'thin' },
right: { style: 'thin' }
}
}
}
}
const filedata = sheet2blob(wb)
openDownloadDialog(filedata, `xxx`)
})
},
/**
* 将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载
* @param sheet excel对象
* @param sheetName
* @returns
*/
sheet2blob(sheet, sheetName?: string) {
const s2ab = (s) => {
const buf = new ArrayBuffer(s.length);
const view = new Uint8Array(buf);
for (let i = 0; i !== s.length; ++i) {
view[i] = s.charCodeAt(i) & 0xFF;
}
return buf;
}
sheetName = sheetName || 'sheet1';
const workbook = {
SheetNames: [sheetName],
Sheets: {}
};
workbook.Sheets[sheetName] = sheet; // 生成excel的配置项
const wopts = {
bookType: 'xlsx', // 要生成的文件类型
bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
type: 'binary'
};
const wbout = XLSX.write(workbook, wopts);
const blob = new Blob([s2ab(wbout)], { // 字符串转ArrayBuffer
type: 'application/octet-stream'
});
return blob;
},
/**
* 创建excel地址并下载到本地
* @param url 文件blob二进制路径
* @param saveName 文件名
*/
openDownloadDialog(url, saveName) {
if (typeof url === 'object' && url instanceof Blob) {
url = URL.createObjectURL(url); // 创建blob地址
}
const aLink = document.createElement('a');
aLink.href = url;
aLink.download = `${saveName}.xlsx`; // HTML5新增的属性,指定保存文件名
let event;
if (window.MouseEvent) {
event = new MouseEvent('click');
} else {
event = document.createEvent('MouseEvents'); // 事件抛出
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
}
aLink.dispatchEvent(event); // 事件派发
}
---本篇还是相当实用,喜欢就一键三连吧~欢迎评论---