「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战」。
前端实现导入导出主要是使用Sheetjs 这个库做转化再加上原生API完成功能,真正上传文件到服务器还是得调用接口,对于真正上传前的预览或者临时导出表格数据到本地等需求,都是完全可以实现的。
导出excel
本文使用的数据类型都是对象数象,其结构也比较符合excel表的结构,其他特殊类型的数据格式暂不深入讨论,对象的各个字段对应excel表的列,一个对象数组就对应一张表。
具体实现分为两步,第一步遍历对象数组将每个对象用JSON.stringify序列化,第二步建议新建一个exportToExcel.js 文件对XLSX提供的函数做一下封装,在里面实现进行新建表,写入,保存等操作,核心代码:
import XLSX from 'xlsx'
...
export default function export2Excel({ worksheets, fileName = 'ExcelFile', type = 'xlsx' } = {}) {
let sheetNames = Object.keys(worksheets)
let workbook = {
SheetNames: sheetNames, //保存的工作表名
Sheets: worksheets,
}
// attempts to write the workbook
let wbout = styleXLSX.write(workbook, options) // options为配置,省略
let wbBlob = new Blob([s2ab(wbout)], {
type: 'application/octet-stream',
})
saveAs(wbBlob, fileName + '.' + type) // save as 函数省略
}
saveAs的实现思路跟点击下载是一样的,先创建一个a标签把href赋值为URL.createObjectURL() 创建出来的DOM string类型的URL,其指向待下载的文件对象, 然后调用click() 函数下载,稍后 (setTimeout等)删掉a标签
导入excel
思路跟上面相反,不同的地方在于,需要用上传组件 在上传组件的 onChange 事件回调里,新建一个FileReader对象,调用对象上的 readAsBinaryString 函数将上传的文件转成二进制流。对象onload 事件里再用XLSX.read 去读取到二进制流遍历每条文件记录,按表头作为对象名,写入到结果数组中。
核心代码:
fileChange(file, fileList) {
if (file && fileList.length > 0) {
const reader = new FileReader()
const _this = this
reader.onload = function (e) {
const data = e.target.result
try {
this.wb = XLSX.read(data, {
type: 'binary',
})
} catch (e) {
_this.$message.error(_this.$t('finance.re_upload'))
}
const result = []
this.wb.SheetNames.forEach((sheetName) => {
result.push({
sheetName: sheetName,
sheet: XLSX.utils.sheet_to_json(this.wb.Sheets[sheetName]),
})
})
}
reader.onerror = (e) => {
console.log('e===>', e)
}
reader.readAsBinaryString(file.raw)
}
},
总结
类似导出的功能虽然前后端都可以做,而且由服务器生成url的形式很方便,但是生成的文件需要在服务器上存储,对于一次性的文件下载比较占服务器资源的,可以酌情去利用客户端实现这些功能为服务器减少压力(访问量大的时候还是比较耗资源的,也可以减少前后端沟通跟联调的时间)。