根据数据动态生成一个Excel导出文件,这个公共相对简单一些,引入 xlsx就可以了。
但是根据需求,动态合并单元格,貌似难度不小,这里需要对 xlsx的属性和方法有一定的了解才可以,那么一起学习一下。
安装 xlsx 和 xlsx-style
cnpm i xlsx xlsx-style --save
excel 示例
A、B、C、D、E、F … 代表的是列
1、2、3、4、5、6、… 代表的是行
每一个单元格是一个对象(Cell Object),主要有t、v、r、h、w等字段:
值 | 注释 |
---|---|
t | 表示内容类型 s表示string类型 n表示number类型 b表示boolean类型 d表示date类型 等等 |
v | 表示原始值; |
f | 表示公式,如B2+B3; |
h | HTML内容 |
w | 格式化后的内容 |
r | 富文本内容rich text |
封装 Export2Excel
import XLSX from 'xlsx'
/**
* xlsx-style 引入会报错,需要 添加下边代码
* // var cpt = require('./cpt' + 'able');
var cpt = cptable
*/
import XLSXStyle from 'xlsx-style'
/**
* 通用的打开下载对话框方法,没有测试过具体兼容性
* @param url 下载地址,也可以是一个blob对象,必选
* @param saveName 保存文件名,可选
*/
function openDownloadDialog(url, saveName)
{
if(typeof url == 'object' && url instanceof Blob)
{
url = URL.createObjectURL(url); // 创建blob地址
}
var aLink = document.createElement('a');
aLink.href = url;
aLink.download = saveName || ''; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
var 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);
}
// 字符串转ArrayBuffer
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
// 将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载
function sheet2blob(sheet, sheetName) {
sheetName = sheetName || 'sheet1';
var workbook = {
SheetNames: [sheetName],
Sheets: {}
};
workbook.Sheets[sheetName] = sheet;
// 生成excel的配置项
var wopts = {
bookType: 'xlsx', // 要生成的文件类型
bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
type: 'binary'
};
var wbout = XLSXStyle.write(workbook, wopts);
var blob = new Blob([s2ab(wbout)], {type:"application/octet-stream"});
return blob;
}
/**
e: {//e结束
c: 3,//结束列
r: 4//结束行
},
s: {//s为开始
c: 0,//开始列
r: 0//可以看成开始行,实际是取值范围
}
*/
function aoa_to_sheet_fn (th,data){
//需要导出的数据
var aoa = [],
// 需要合并的单元格
mergeArr =[],
// 需要更改样式的单元格
colArr = {},
// 字母 代表列
letter =['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O'];
// 表头样式
th.map((m,i)=>{
colArr[letter[i]+'1'] = {
font: {
sz: 15,
bold: true,
color: {
rgb: "FFFFAA00"
}
},
alignment: {
horizontal: "center",
vertical: "center",
wrap_text: true
}
}
})
// 将表头数据,添加到数组第一项
aoa.unshift(th);
// 遍历需要显示的数据,规则根据需求,自行封装
data.map((m)=>{
...
// 需要合并的单元格
mergeArr.push({
s: {r:xxx, c: 0},
e: {r: xxx, c: 0}
})
// 此处代表A2行,字体为14px 居中显示
colArr['A2'] = {
font: {
sz: 14
},
alignment: {
horizontal: "center",
vertical: "center"
}
}
aoa.push('这里添加需要展示的数据')
...
})
var sheet = XLSX.utils.aoa_to_sheet(aoa);
/**
* 举例:第一列到第三列合并--等于--设置A1-C1的单元格合并:[
{s: {r: 0, c: 1}, e: {r: 0, c: 3}}
];
*/
// 需要合并的单元格-- 赋值
sheet['!merges'] = mergeArr
//控制单元格宽度
sheet["!cols"] = [{
wpx: 200
}, {
wpx: 150
}, {
wpx: 150
}, {
wpx: 150
}];
// 样式 赋值
for(let i in colArr){
sheet[i].s =colArr[i]
}
// 输出
return sheet
}
export function export_json_to_excel(th, data, defaultTitle) {
var sheet = aoa_to_sheet_fn(th, data)
openDownloadDialog(sheet2blob(sheet), defaultTitle +'.xlsx'|| '表名.xlsx');
}
知识扩展
使用xlsx 时,会报错
This relative module was not found:
* ./cptable in ./node_modules/xlsx-style/dist/cpexcel.js
解决:
修改 vue.config.js 文件 chainWebpack
...
chainWebpack: (config) => {
config.resolve.alias
// 移除 prefetch 插件
// config.plugins.delete('prefetch')
.set('@',resolve('src'))
.set('$api', resolve('src/api'))
config.externals({ './cptable': 'var cptable' })
}
....