好多年没有搬砖了,最近看微信小程序比较好玩,就试着搞几个小程序玩一玩。因为是业余的,主要是面向需求编程,面向百度/bing编程。不过一些相关的代码的奇奇怪怪的问题,搜索引擎都会最终带领我到CSND/ JianShu / CNblogs这几个地方 。
最近有一个需求是把Json数组导出到excel, 搜了一下,主要有2种路线:
1. 预先处理好的xls文件,存入wx cloud,
2. 云函数,安装node-xlsx或是excel-export 类库(node类库),这总方式更加灵活,可以读取数据库然后直接生成excel保存到wx cloud
然后获取云路径,复制到浏览器下载,或是直接用 wx.open打开;
也有狠人,直接用把这两个库放或是js-xlsx 的dist复制出来,例如js-xlsx的xlsx.full.min.js引入到微信页面中,通过前端搞定,好像也可以的。不过就是更麻烦一点,而且比较咱空间,几百K就没了。
但实际上我的需求很简单,没那么复制,所以我最终选择了一个更简单的路线:
1. 小数据直接复制到剪贴板
2. 稍微多一点的数据写入xml.xls,用微信打开,步骤:
Json数组--> 遍历生成xml格式的excel --> wx.getFileSystemManager.writeFile-->wx.openDocument 代码不多,逻辑也简单。上图:
原理:
excel也是xml格式的,并且excel可以打开符合最小规范的xml:
- 工作表的名称(worksheet 标签下的 ss:Name),一般默认就是 Sheet 1
- 每个Cell下面的数据类型(Data 标签下的 ss:Type),一般默认为String,S要大写。当然你也可能更精确一点判断其他数据格式,如数字,货币等等。
<? xml version="1.0" ?>
<? mso-application progid="Excel.Sheet" ?>
< Workbook xmlns ="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o ="urn:schemas-microsoft-com:office:office"
xmlns:x ="urn:schemas-microsoft-com:office:excel"
xmlns:ss ="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html ="http://www.w3.org/TR/REC-html40" >
< Worksheet ss:Name ="Sheet1" >
< Table >
< Row >
< Cell >< Data ss:Type ="String" >Hello!</ Data ></ Cell >
</ Row >
</ Table >
</ Worksheet >
</ Workbook >
头尾固定,就是需要在<Table></Table>中一行一行的插入。遍历Json数组,可以是数据库的查询结果,例如[{a:0,b:1},{a:1,b:2},{a:2,b:3}],另外考虑给数据加上一个表头,通过数组插入一行,例如['数量1','数量2']
简单封装一下函数如下:
json2xls(data,header){
//data 为Json数组, Header为字符串数组
const XMLSheets = data
// 检查是否有数据
if (!XMLSheets || !XMLSheets.length) { return {err:'空数据'}}
// excel 头部
var XMLString = `
<?xml version="1.0" encoding="UTF-8"?>
<?mso-application progid= "Excel.Sheet"?>`
XMLString += `<Workbook
xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">`
XMLString += `<Worksheet ss:Name="sheet 1">`
// Table 头部
XMLString += '<Table>'
//遍历header插入Frist Row, Header
XMLString+='<Row>'
header.forEach((hd, i)=>{
XMLString+='<Cell>'+`<Data ss:Type="String">`+hd+'</Data></Cell>'
})
XMLString+='</Row>'
// 遍历Data,插入数据Row
XMLSheets.forEach((row) => {
// 遍历数组,插入行
XMLString += '<Row>'
// 遍历Json,插入单元格
for(var p in row){
// Cell 头部
XMLString += `<Cell><Data ss:Type="String">${row[p]}</Data></Cell>`
}
XMLString += '</Row>'
}) // 便利 Cell
// Table 尾部
XMLString += '</Table>'
// Worksheet 尾部
XMLString += '</Worksheet></Workbook>'
console.log(XMLString)
return XMLString
},
把以下函数bindtap到一个按键就可以了, 可以自行赋值header 和jsonData的数据,这个函数会调用上面的函数把json转成xml字符串,然后写入临时文件,让wx.opendocument打开。
exportxls(){
let header=['数据1','数据2']
let jsonData=[{a:0,b:1},{a:1,b:2},{a:2,b:3}]
let xlsdata=this.json2xls(jsonData,header)
const fsm = wx.getFileSystemManager();
fsm.writeFile({
filePath: wx.env.USER_DATA_PATH + '/tmp.xls',
data: xlsdata,
encoding: 'utf8',
success: res => {
console.info(res)
//open it
wx.openDocument({
filePath: wx.env.USER_DATA_PATH + "/tmp.xls",
success: function(res) {
console.log('打开文档成功')
},
fail: function() {
console.log('打开失败');
}
})
},
fail: res => {
console.info(res)
}
})
},
简单粗糙,但是是可以run的,大家可以复制到你的小程序页面里面试一试吧。
临时文件为tmp.xls,多次使用会自动覆盖。连续打开多个可能会存在文件锁定的问题。你也可以使用随机文件名或是自定义文件名,但是会产生很多垃圾。
打开xls时可能会有提示,选择‘是’打开另存一下就可以了。另外所有的数字都被当成字符串了,有必要的话需要用户在excel里面再转换。你也可以自己在json2xls里面自己判断,数据类型为<Data ss:Type="Number">
如果需要更精确的控制,例如列宽,颜色样式等等,可以通过这个文章自行定义: