前言

最近在弄一个Electron小项目,需要生成并导出Excel文件,踩到了一些坑,记录一下,避免以后再翻车。

正文

eletron进程分为主进程和渲染进程,文件导出在两个进程中实现不一样,这里主要讲使用json导出excel,其他格式导出方法类似,话不多说,直接上代码

在渲染进程中使用

第一步: 安装 file-saver 和 xlsx

1
yarn add file-saver xlsx

第二步:在要用的组件用中引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import FileSaver from 'file-saver'
import XLSX from 'xlsx'

// 需要导出的json
const json =[{
'name':'weylan',
'sex':'男',
'age':18
}]

const exportExcel = ()=>{
const wb = XLSX.utils.book_new()
const header = [['name','sex','age']]
const ws = XLSX.utils.json_to_sheet(data,{header:header})
XLSX.utils.book_append_sheet(wb,ws)
const wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: true, type: 'array'});
try {
FileSaver.saveAs(new Blob([wbout], {type: 'application/octet-stream'}), '导出数据.xlsx');
} catch (e) {
if (typeof console !== 'undefined')
console.log(e, wbout)
}
}

在渲染进程中导出excel就是这么简单。一些高阶的用法,请参考文档 [https://www.npmjs.com/package/xlsx]

在主进程中使用

因为electron主进程是node环境,使用以上代码会报 Referenceerror blob is not defined node,因为node.js 没有Bolb,需要使用Buffer,但这里我并不打算用,xlsx提供了很方便的写文件方法。见代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

import XLSX from 'xlsx'
import { dialog } from 'electron'

// 需要导出的json
const json =[{
'name':'weylan',
'sex':'男',
'age':18
}]
const exportExcel = ()=>{
// 使用electron 自带的文件保存弹窗选择目录
let path = await dialog.showSaveDialog({title:'xxx导出',defaultPath:'xxx'})
if(!path.filePath){ // 取消会返回undefined
return
}
const wb = XLSX.utils.book_new()
const header = [['name','sex','age']]
const ws = XLSX.utils.json_to_sheet(data,{header:header})
XLSX.utils.book_append_sheet(wb,ws)
XLSX.writeFile(wb,`${path.filePath}.xlsx`,{bookType: 'xlsx', bookSST: true, type: 'array'})
}

自此,electron 导出excel 已初步完成,但有时我们在开发时需要自定义header,或者传多了列,但并不需要在excel体现,我这里给了初步的封装:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

/**
* 处理header信息,将第一行改写成自定义名称,同时去掉多余的列
* @titles ['name','sex','age']
*/
_handelSheetHeader = (ws:XLSX.WorkSheet,titles:any)=>{
if(!titles) {
return
}
const range = XLSX.utils.decode_range(ws['!ref'] as string)
for(let c = range.s.c; c <= range.e.c; c++) {
let col = XLSX.utils.encode_col(c)
const header = col + '1'
if(!titles[ ws[header].v ]){
for(let d = 1 ;d<=range.e.r+1;d++){
delete ws[''+col+d]
}
continue
}
ws[header].v = titles[ ws[header].v ]
}
}

有不对之处,欢迎指正 :)