前端json转excel 到zip下载

发布时间 2023-12-19 20:57:45作者: 辛夷不改年年色

问题描述:后端返回数据原先返回是多个json文件的压缩包二进制文件流,前端直接下载二进制文件流。但是客户要求下载excel类型文件。

解决方案:前端拿到表格的json数据转换成对应table的html字符串,使用插件js-xlsx。

给个链接

import * as XLSX from 'xlsx'
// JSONData为导出的json数据,fileName为导出的文件名,title为导出的第一行标题,filter为过滤字段
export default (JSONData, FileName, title, filter)=>{
  if (!JSONData) { return }
  // 转化json为object
  //var arrData = typeof JSONData !== 'object' ? JSON.parse(JSONData) : JSONData

  let excel = '<table class="htmlTable">'
  for(let i =0;i<JSONData.length;i++){
    const rowData = JSONData[i]
    const rowDatakeyList = Object.keys(rowData)
    let value = 0
    for(let j=0;j<rowDatakeyList.length;j++){
      const item = rowData[rowDatakeyList[j]]
      if(item.value){
        value++
      }
    }
    if(!value){
      continue
    }
    
      let row = '<tr>'
      for(let j=0;j<rowDatakeyList.length;j++){
        const item = rowData[rowDatakeyList[j]]
        row=row+`<td style="text-align:center;vertical-align:middle">${item.value||''}</td>`
      }
      excel =`${excel}${row}</tr>`
    }
  excel = excel +'</table>'
  var objE = document.createElement('div') // 因为我们这里的数据是string格式的,但是js-xlsx需要dom格式,则先新建一个div然后把数据加入到innerHTML中,在传childNodes[0]即使dom格式的数据
  objE.innerHTML = excel
  var sheet = XLSX.utils.table_to_sheet(objE.childNodes[0], { raw: true })// 将一个table对象转换成一个sheet对象,raw为true的作用是把数字当成string,身份证不转换成科学计数法
  return sheet2blob(sheet, FileName) // 因为我需要多个excel构成的压缩包,所以我在这里直接返回二进制文件流
  // openDownloadDialog(sheet2blob(sheet, FileName), FileName + '.xlsx') // 若想下载excel文件使用这行
}

// 将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载
function sheet2blob(sheet, sheetName) { // sheetName是文件名,不能超过31.这个是插件内部限制
  sheetName = sheetName || 'sheet1' // 不存在sheetName时使用sheet1代替
  var workbook = {
    SheetNames: [sheetName],
    Sheets: {}
  }
  workbook.Sheets[sheetName] = sheet // 生成excel的配置项
  workbook.Sheets[sheetName]['!cols'] = [    //生成excel的列的宽度
                      // { wch: 20 }, // 第一列
                      // { wch: 40 }, // 第二列
                      // { wch: 80 }  // 第三列
]

  var wopts = {
    bookType: 'xlsx', // 要生成的文件类型
    bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
    type: 'binary' // 二进制格式
  }
  var wbout = XLSX.write(workbook, wopts)
  var blob = new Blob([s2ab(wbout)], {
    type: 'application/octet-stream'
  }) // 字符串转ArrayBuffer
  function s2ab(s) {
    var buf = new ArrayBuffer(s.length)
    var view = new Uint8Array(buf)
    for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF
    return buf
  }
  return blob
}
// 下载的方法
function openDownloadDialog(url, saveName) {
  if (typeof url === 'object' && url instanceof Blob) {
    url = URL.createObjectURL(url) // 创建blob地址
  }
  var aLink = document.createElement('a')
  aLink.href = url
  aLink.download = saveName || '' // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
  var event
  if (window.MouseEvent) event = new MouseEvent('click')
  else {
    event = document.createEvent('MouseEvents')
    event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
  }
  aLink.dispatchEvent(event)
}

拿到二进制文件流后,需要放在一起进行压缩

使用的是这两个插件  jszip   file-saver

再给个链接,这个好看一点

/**
     * 外部调用下载excel表格
     */
    downLoadExcelByFormOcr() {
      const zip = new JSzip() 
        for(let i=0;i<this.picData.length;i++){
          const item = this.picData[i]
          let subName = item.dataName.substring(0, item.dataName.lastIndexOf(".")); // 设置文件名
          const file = JSONToExcelConvertor(this.formatTableResult(item), `tempFile_${i+1}`);
      // 这个就是拿到上个方法返回的二进制文件流,第二个参数是随便写的文件名,为了过jsexcel的文件名(这个文件名用不到,所以随便写的) zip.file(`${subName}.xlsx`, file)
      // 当把文件放进压缩包中时,又设置了一遍文件名,这个是最后生效的文件名 } zip.generateAsync({ type:
'blob' }).then(content2 => { saveAs(content2, 'excelFile.zip') // 下载,content2 是方法返回压缩包数据,第二个参数是压缩包名称
}) },

这三个函数都是将json转格式为了方便后面方法生成html字符串。不用理会