vue3+vite项目使用xlsx+xlsx-style+file-saver导出带有样式的excel表格方法
基于vue3+vite的项目实现导出带有样式的excel表格,框架用的是vben,我的版本为“xlsx”: “^0.16.9”,“xlsx-style”: “^0.8.13”“file-saver”: “^2.0.5”,
·
基于vue3+vite的项目实现导出带有样式的excel表格,框架用的是vben,所以表格用的是ant的table组件数据源,如果用原生表格需要用到备注的另外方法。
- 首先需要下载xlsx、xlsx-style、file-saver这3个依赖。
npm i xlsx xlsx-style file-saver
我的版本为
“xlsx”: “^0.16.9”,
“xlsx-style”: “^0.8.13”
“file-saver”: “^2.0.5”,
- 下载完成后xlsx-style会有很多报错,具体的解决方法可以参考xlsx-style坑记录,我按照他的方式所有都改了一遍,没有出现过报错问题。
另外它的样式设置无法修改行高,所以需要再修改一下源码,修改xlsx-style文件夹下面的xlsx.js文件 替换write_ws_xml_data以下方法
var DEF_PPI = 96, PPI = DEF_PPI;
function px2pt(px) { return px * 96 / PPI; }
function pt2px(pt) { return pt * PPI / 96; }
function write_ws_xml_data(ws, opts, idx, wb) {
var o = [], r = [], range = safe_decode_range(ws['!ref']), cell, ref, rr = "", cols = [], R, C,rows = ws['!rows'];
for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
for(R = range.s.r; R <= range.e.r; ++R) {
r = [];
rr = encode_row(R);
for(C = range.s.c; C <= range.e.c; ++C) {
ref = cols[C] + rr;
if(ws[ref] === undefined) continue;
if((cell = write_ws_xml_cell(ws[ref], ref, ws, opts, idx, wb)) != null) r.push(cell);
}
if(r.length > 0){
params = ({r:rr});
if(rows && rows[R]) {
row = rows[R];
if(row.hidden) params.hidden = 1;
height = -1;
if (row.hpx) height = px2pt(row.hpx);
else if (row.hpt) height = row.hpt;
if (height > -1) { params.ht = height; params.customHeight = 1; }
if (row.level) { params.outlineLevel = row.level; }
}
o[o.length] = (writextag('row', r.join(""), params));
}
}
if(rows) for(; R < rows.length; ++R) {
if(rows && rows[R]) {
params = ({r:R+1});
row = rows[R];
if(row.hidden) params.hidden = 1;
height = -1;
if (row.hpx) height = px2pt(row.hpx);
else if (row.hpt) height = row.hpt;
if (height > -1) { params.ht = height; params.customHeight = 1; }
if (row.level) { params.outlineLevel = row.level; }
o[o.length] = (writextag('row', "", params));
}
}
return o.join("");
}
- 完成上述步骤就可以直接使用,完整引用代码以及方法如下:
import XLSX from 'xlsx';
import XLSXS from 'xlsx-style';
import FileSaver from 'file-saver';
// 导出excel方法
const exportExcel = () => {
// 第一种是经过处理后的数据
tableData = [
['第一行第一列', '第一行第二列', '第一行第三列'],
['第二行第一列', '第二行第二列', '第二行第三列'],
['第三行第一列', '第三行第二列', '第三行第三列'],
]
const wsa = XLSX.utils.aoa_to_sheet(tableData);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, wsa, '数据表');
// 第二种是原生table的数据格式,需要dom获取表格数据
// let wsa = XLSX.utils.table_to_book(this.$refs.table, { sheet: "数据表" });
// 样式添加
xlsxAddStyle(wsa, tableData[0].length);
var wopts = {
bookType: 'xlsx', // 要生成的文件类型
bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
type: 'binary',
};
var ws = XLSXS.write(wb, wopts);
try {
FileSaver.saveAs(new Blob([s2ab(ws)], { type: 'application/octet-stream' }), `配置.xlsx`);
} catch (e) {
if (typeof console !== 'undefined') console.log(e, ws);
}
// 字符串转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;
}
};
// 表格样式的设置
const xlsxAddStyle = (sheet, rowCLength) => {
const mergeArr = []; // 合并的单元格
const rowH = []; // 表格每列高度
const rowC = []; // 表格每列宽度
// 单元格外侧有框线
const borderAll = {
top: { style: 'thin' },
bottom: { style: 'thin' },
left: { style: 'thin' },
right: { style: 'thin' },
};
// 单元格外侧无框线
const noBorder = {
top: { style: '' },
bottom: { style: '' },
left: { style: '' },
right: { style: '' },
};
for (const key in sheet) {
if (Object.hasOwnProperty.call(sheet, key)) {
const element = sheet[key];
if (typeof element === 'object') {
const index = Number(letter(key)) - 1;
rowH[index] = { hpx: 20 };
element.s = {
alignment: {
horizontal: 'center', // 所有单元格水平居中
vertical: 'center', // 所有单元格垂直居中
},
font: {
name: '宋体',
sz: 12,
italic: false,
underline: false,
},
border: borderAll,
fill: {
fgColor: { rgb: 'FFFFFFFF' },
},
};
// 指标值表格的样式
// if (key.indexOf('C') > -1) {
// element.s.alignment.horizontal = 'right';
// }
// 标题的样式
if (index === 0) {
element.s.font.bold = true;
element.s.fill.fgColor = { rgb: 'FFCCFFFF' };
}
// 处理合并单元格数组 s开始 e结束 r行 c列
// if (element.v === '所属设备') {
// mergeArr.push({
// s: { r: 0, c: 0 },
// e: { r: 2, c: 1 },
// });
// }
}
}
}
// 单元格的列宽,根据传入的列数进行逐个添加
for (let i = 0; i < rowCLength; i++) {
rowC.push({ wpx: 180 });
}
sheet['!cols'] = rowC;
// 单元格的行宽
sheet['!rows'] = rowH;
// 合并单元格
sheet['!merges'] = mergeArr;
return sheet;
};
// 去除字母方法,当列的数量超过25的时候会变成AA所以需要用正则匹配去掉所有的字母,剩下数字
const letter = (str) => {
let result;
const reg = /[a-zA-Z]+/;
while ((result = str.match(reg))) {
//判断str.match(reg)是否没有字母了
str = str.replace(result[0], ''); //替换掉字母 result[0] 是 str.match(reg)匹配到的字母
}
return str;
};
更多推荐
已为社区贡献11条内容
所有评论(0)