uniapp app端导出excel的探索和实现
使用uniapp生成excel并写入appdocuments目录下,在此基础上修改部分源码,来更改excel单元格样式
前言
最近接触了一个使用uniapp写的app,其中有个导出Excel的功能,在此做一下总结。
最终结果
app端生成excel,修改部分单元格参数(文字居中,单元格类型为文本),最后导出.xlsx文件到该app的documents目录下。
一些问题
0.Blob or html
在uniapp中导出excel,铺天盖地的都是sheetjs + Blob,然后一顿下载,那是在H5!app里面压根就没有blob对象。(这里引发另一个思考,就是在app端使用webview,这样就能有Blob对象了,没试过,感觉应该是可行的。)
app中,需要使用系统IO流来创建.xlsx文件,然后写入数据。如果写入的是下面的HTML模板,就可以用excel打开了:
let worksheet = "sheet1";
let tableHtml= '<tr><td>姓名</td><td>电话</td><td>邮箱</td></tr>'
// 循环遍历,每行加入tr标签,每个单元格加td标签
for (let i = 0; i < jsonData.length; i++) {
tableHtml+= '<tr>'
for (let item in jsonData[i]) {
// 增加\t为了不让表格显示科学计数法或者其他格式
tableHtml += `<td>${jsonData[i][item] + '\t'}</td>`
}
tableHtml+= '</tr>'
}
//下载的表格模板数据
let template = `<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns="http://www.w3.org/TR/REC-html40">
<head><!--[if gte mso 9]><xml encoding="UTF-8"><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet>
<x:Name>${worksheet}</x:Name>
<x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>
</x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]-->
</head><body>${tableHtml}</body></html>`;
先不用急着复制, tableHtml
是可以通过sheetJS转换的,下面会提到,当然你自己循环生成也能用,可以直接看保存的实现。
1.SheetJS or xlsx-js-style
我们页面中的数据一般都是数组对象类型的,sheetJS可以转换json为html,省去一部分思考。
SheetJS: https://github.com/SheetJS/sheetjs
SheetJS中文文档: https://github.com/rockboom/SheetJS-docs-zh-CN/
SheetJS这个库确实挺牛的,但是它的社区版本不支持修改单元格样式,需要升级到Pro版本,然后就是要你发邮件给作者申请,巴拉巴拉。但是!简单的单元格样式修改是可以通过修改源码来达成的。笔者这里主要是居中对齐和单元格数据类型必须是文本类型,完全够用了。
再来说下xlsx-js-style。
xlsx-js-style : https://github.com/gitbrent/xlsx-js-style
官方的描述是 SheetJS Community Edition
+ Basic Cell Styles
,听起来不错,但是因为app中保存文件的原因,没有采用。
实现
思路是这样的:
- 修改sheetJS部分源码,满足单元格样式需求
- 使用sheetJS转换JSON为html文本(需要取出table标签,注入到准备好的html模板中)
- 使用H5+ api保存文件
先从github上将 xlsx.core.min.js 下载到项目中。
1.单元格居中 & 设置文本类型
源码中搜索 s[“data-v”] 可以找到需要编辑的位置:
此处新增一行代码:
s["style"] = "text-align: center; mso-number-format:'\@'";
笔者通过观察,发现这里的s就是单元格对象,转化为html时候,s上的属性会被写为单元格的行内式,text-align: center
不用解释了,mso-number-format:'\@'"
意思是将此单元格数据类型设置为自定义类型,值为@
。
有人说,你不是设置成文本类型吗,怎么又弄成自定义类型了。笔者打开excel验证过,当设置一个单元格格式为自定义类型,值为@的时候,再查看该单元格类型,就会自动变为文本类型。
原因我也查过,在excel中@是引用单元格的原文,所以你只写一个@,其实就是原文显示,最终经历了一些不为人知的类型处理,就摇身一变,成了文本类型。感兴趣可以看下这篇文章:Excel自定义格式之“@”符号
2.使用sheetJS转换JSON为html文本
数据格式如下:
excelData: [
{
no: "1",
tag: "weqwrqwrqwrqwrq",
remark: "22",
},
{
no: "2",
tag: "342343434343",
remark: "33",
},
{
no: "3",
tag: "25125152512",
remark: "44",
},
],
转换为html:
const sheet = XLSX.utils.json_to_sheet(this.excelData);
const htmlSheet = XLSX.utils.sheet_to_html(sheet);
这里导出的html是一个完整的包含html标签的字符串,而我们只需要table标签的内容,使用正则提取下:
const pattern = /<table(?:(?!<\/table>).|\n)*?<\/table>/;
const tableHtml = htmlSheet.match(pattern)[0];
最终获取到完整的模板:
const writeData = this.tableToExcel(tableHtml);
function tableToExcel(tableHtml) {
//列标题
let worksheet = "sheet1";
//下载的表格模板数据
let template = `<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns="http://www.w3.org/TR/REC-html40">
<head><!--[if gte mso 9]><xml encoding="UTF-8"><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet>
<x:Name>${worksheet}</x:Name>
<x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>
</x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]-->
</head><body>${tableHtml}</body></html>`;
return template;
},
使用H5+ api保存文件
这里主要使用的是io接口,文档在此:html5plus io文档
保存文件代码如下:
// #ifdef APP-PLUS
plus.io.requestFileSystem(plus.io.PUBLIC_DOCUMENTS, function(fs) {
let root = fs.root;
// 直接在 documents 中创建文件
root.getFile(
`${new Date().getTime()}.xlsx`,
{
create: true,
},
(fileEntry) => {
fileEntry.createWriter(
(writer) => {
// 写入数据
writer.write(writeData);
// 写入文件成功完成的回调函数
writer.onwrite = (e) => {
uni.showToast({
title: `导出成功`,
icon: "none",
});
};
},
(err) => {
console.log(err, "创建文件写入器错误");
}
);
},
(err) => {
console.log(err);
}
);
});
// #endif
关于app存储目录的问题,可以看这篇文章: plus.io
io的api一层套一层,需要自己耐心体会,一定可以达到目的!
至此,导出excel功能就收官了!
以上!
更多推荐
所有评论(0)