最近在做一些纯前端导出的功能,要求excel需要有一些格式、样式的调整,当时想使用excel模板然后读取模板从种写数的,通过设置模版的特殊位置字符,读取模板进行直接替换。发现由于动态数据的局限性,还是打算直接使用js去生成一个excel文件。开始使用的xlsx.js进行开发,利用xlsx-style进行样式设置,xlsx支持的api的能够实现的功能相对比较多的,(由于xlsx-style引用报错问题,可以使用real-xlsx-style代替),在实际开发中,虽然xlsx实现了很多功能,但是发现xlsx-style设置单元格超链接设置不上、并且每个设置了样式的单元格,内容都会被初始化,(文档太少了,不建议使用,可以研究研究),后面决定使用excel.js进行导出。
通过aoa 数据转换为excel文件
const aoa_to_excel = (aoa, opts) => {
opts = opts || {};
const sheetName = opts.sheetName || "sheet1";
const workbook = new ExcelJS.Workbook();
const ws = workbook.addWorksheet(sheetName, opts.sheetConfig);
for(let i = 0, length = aoa.length; i < length ; i++){
for(let j = 0, len = aoa[i].length; j < len; j++ ) {
const cell = ws.getRow(i + 1).getCell(j + 1);
cell.value = aoa[i][j];
// 设置地址为超链接
if(opts.openHrefLink && typeof aoa[i][j] === 'string' && /^(http:|https:)/.test(aoa[i][j])){
cell.value = {
text: aoa[i][j],
hyperlink: aoa[i][j],
tooltip: aoa[i][j]
};
cell.font = { underline: true, color: { argb: 'FF315EFB'} }
}
// 设置默认样式
if(opts.defaultCellStyle) {
const defaultStyle = opts.defaultCellStyle;
if(defaultStyle.alignment) {
cell.alignment = { ...defaultStyle.alignment, ...(cell.alignment || {})}
}
if(defaultStyle.border) {
cell.border = { ...defaultStyle.border, ...(cell.border || {})}
}
if(defaultStyle.font) {
cell.font = { ...defaultStyle.font, ...(cell.font || {})}
}
if(defaultStyle.fill) {
cell.fill = { ...defaultStyle.fill, ...(cell.fill || {})}
}
}
if(typeof opts.onCustomCell === 'function') {
opts.onCustomCell(cell, i + 1, j + 1)
}
}
}
// 处理列
if(opts.columnsConfig instanceof Array) {
ws.columns = (ws.columns || []).map((v, index) => {
const config = opts.columnsConfig[index] || {};
return { ...v, ...config }
})
}
// 处理合并
if(opts.merges instanceof Array) {
opts.merges.forEach(item => {
if(item instanceof Array && item.length <= 2) {
ws.mergeCells(...item)
}else if(typeof item === 'string') {
ws.mergeCells(item)
}
})
}
// 下载文件
workbook.xlsx.writeBuffer().then((buffer) => {
const fileName = opts.fileName || sheetName + '.xlsx';
let blob = new Blob([buffer], { type: "application/octet-stream" });
download(URL.createObjectURL(blob), fileName);
});
}
文件下载
下面的文件下载针对创建a标签然后通过click点击的方式更有效
const download = (url, saveName) => {
if (typeof url === "object" && url instanceof Blob) {
url = URL.createObjectURL(url); // 创建blob地址
}
let aLink = document.createElement("a");
aLink.href = url;
aLink.download = saveName || ""; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
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);
}
调用
const aoa = [
["测试1", null, "测试2", null],
["测试3", null, "测试4", null],
[null, null, null, null], // 空行
// …otherAoa
];
const configOpts = {
fileName: ‘附件名称.xlsx',
openHrefLink: true, // 开启自动匹配带http、https开头的地址为超链接
defaultCellStyle: { // 默认样式
font: { name: '宋体', size: 10, color: 'FFFF00' },
alignment: { vertical: 'top', horizontal: 'left', wrapText: false, indent: 0 },
border: {
top: {style:'thin'},
left: {style:'thin'},
bottom: {style:'thin'},
right: {style:'thin'}
},
},
columnsConfig: [ // 列配置
{ width: 15 },
{ width: 26 },
{ width: 50 },
{ width: 15 },
],
merges: [ 'B1:C1', 'E1:F1', 'B2:C2', 'E2:F2', 'B3:F3' ], // 需要合并单元格
onCustomCell: (cell, row, cell) => { // 自定义cell回调
if(row === 4) {
cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: "FFFFFF00" } };
}
if( cell === 1 && (cell > 4 && cell % 4 === 1)) {
cell.font = { name: '宋体', sz: 10, color: { argb: "FFFF0000" }}
}
}
}
excelTool.aoa_to_excel(aoa, configOpts) // 导出文件