总结前端导入导出Excel

353 阅读2分钟

「这是我参与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的形式很方便,但是生成的文件需要在服务器上存储,对于一次性的文件下载比较占服务器资源的,可以酌情去利用客户端实现这些功能为服务器减少压力(访问量大的时候还是比较耗资源的,也可以减少前后端沟通跟联调的时间)。