阅读 1496

前端文件下载导出Excel

前言

之前在工作中,有遇到过需要导出Excel的需求, 这里整理了一下,一般前端在导出excel时, 多分为两种, 一种是后端返回二进制数据流, 另一种是直接纯前端生成(如导出一个模板). 而导出的方式可以使用form表单提交, a标签下载, window.open打开新窗口. 最常用的应该就是a标签了.

正文

这里主要讲两种方式的文件下载方法, 和后端返回二进制数据流时,产生乱码,及数据量过大导致网络失败的解决方法.

1.纯前端生成EXcel, 这里更新一下, 增加导出xlsx格式的方法

这种方法用的不多,一般文件下载还是主要依赖于后端返回二进制数据流的形式实现. 这种方法一般用于json格式数据导出模板 话不多说,先上代码

```
 let str = ''
  const jsonData = [{ '仓库代码': '', '货号': '', '尺码': '', '条码': '', '切货数量': '', '折扣': '' }]
  console.log(jsonData)
  for (var k in jsonData[0]) {
    str += k + ','
  }
  str = str.slice(0, str.length - 1) + '\n'
  console.log(str)
  // 增加\t为了不让表格显示科学计数法或者其他格式
  for (let i = 0; i < jsonData.length; i++) {
    for (const item in jsonData[i]) {
      str += `${jsonData[i][item] + '\t'},`
    }
    str += '\n'
  }
  // encodeURIComponent解决中文乱码
  const uri = 'data:application/vnd.ms-excel;charset=utf-8,\ufeff' + encodeURIComponent(str)
  // 通过创建a标签实现
  const link = document.createElement('a')
  link.href = uri
  // 对下载的文件命名
  link.download = '订单模板.xls'
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
```
复制代码

导出xlsx格式

第一步: 安装 file-saver 和 xlsx

 npm i file-saver xlsx -s
复制代码
第二步: 在要用的组件用中引入
复制代码
  import FileSaver from 'file-saver'
 import XLSX from 'xlsx'
复制代码
// 为表格绑定一个id, 特别注意
<el-table
   id="table"
   :data="tableData"
   style="width: 100%">
   <el-table-column
     prop="date"
     label="日期"
     width="180">
   </el-table-column>
   <el-table-column
     prop="name"
     label="姓名"
     width="180">
   </el-table-column>
   <el-table-column
     prop="address"
     label="地址">
   </el-table-column>
 </el-table>
复制代码

第三步:绑定导出按钮的调用方法

getXlsx() {
             let wb = XLSX.utils.table_to_book(document.querySelector('#table'));
             /* #table 就是表格的id */
             let 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)
             }
             return wbout


         },

复制代码

2.后端返回二进制数据流,生成Excel

对于导出数据而言,返回二进制流文件是最常见的, 而前端打开链接下载excel文件一般有三种方式, 
第一种是form表单方式 , 也是同步下载方式,直接下载. 这种方式的优点在于不需要对返回数据进行转换操作, 浏览器会自动同步解析. 但缺点是无法对返回结果进行操作, 如:一般工作中需要对请求进行鉴权, 这个时候,form表单方式下载是无法在请求头中带上token的, 后端只能通过从cookie中获取.

第二种是a标签下载方式, 将返回结果处理成一个新链接, 通过创建a标签打开, 这种方式的优点在于内部请求不需要对鉴权做多余处理, 也可以拿到返回结果进行操作,
缺点在于不注意之间会产生乱码,及数据量太大导致网络失败. 
使用blob容器可以解决数据量大导致网络失败的问题, 
而乱码问题在二进制流前拼接字符串'\ufeff'即可
```
 this.$axios({
      method: params.method,
      url: params.url,
      data: params.data,
      responseType: 'blob'  // 指明返回格式, 这里注明一下, 如果导出EXCEL为[object blob]的话, 可以把这段responseType:'blob' 注释掉试一下.  
    }).then(res => {
      console.log(res) // 返回结果
      // 这里尤其需要注意, '\ufeff' 用于解决乱码问题, blob可以解决数据量大导致网络失败.
      const blob = new Blob(['\ufeff' + res.data], { type: 'text/csv;charset=utf-8' })
      const url = window.URL.createObjectURL(blob)
      // 通过创建a标签实现
      const link = document.createElement('a')
      link.href = url
      // 对下载的文件命名, 如果后端返回名称出现乱码, 需要后端编码一下.
      link.download = decodeURI(res.headers['content-disposition'].split('=')[1]) || '发货单导出数据表.csv'
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
    })
```
复制代码

结语

功能不难,需要注意的是二进制流的转换, 和a标签地址太长导致网络失败的问题就行.

关注下面的标签,发现更多相似文章
评论