前言
之前在工作中,有遇到过需要导出Excel的需求, 这里整理了一下,一般前端在导出excel时, 多分为两种, 一种是后端返回二进制数据流, 另一种是直接纯前端生成(如导出一个模板). 而导出的方式可以使用form表单提交, a标签下载, window.open打开新窗口. 最常用的应该就是a标签了.
正文
这里主要讲两种方式的文件下载方法, 和后端返回二进制数据流时,产生乱码,及数据量过大导致网络失败的解决方法.
新增: 这里添加一个纯前端读取数据并解析
重点 : 这里需要用到的插件有两个,
import FileSaver from 'file-saver'
import XLSX from 'xlsx'
首先 我们需要拿到要解析的文件, 可以使用element-ui里的upload组件(只是举例,具体没有限制,只要拿得到上传的文件), 然后再httprequest那个上传方法里获取它的file,
然后, 我们把拿到的file作为形参放到解析的方法里,就可以了
async uploadFile(file) {
const _file = file
const fileReader = new FileReader()
fileReader.onload = (ev) => {
try {
const data = ev.target.result
const workbook = XLSX.read(data, {
type: 'binary'
})
for (const sheet in workbook.Sheets) {
// 循环读取每个文件
const sheetArray = XLSX.utils.sheet_to_json(workbook.Sheets[sheet])
// 若当前sheet没有数据,则continue
if (sheetArray.length === 0) {
continue
}
// arr 可以是需要存放数据的数组
const arr = []
// 这里可以打印下, 可以拿到键值对形式的解析数据, 之后就可以自己去操作了
sheetArray.forEach(e => {
const rowTable = {}
for (const item in e) {
if (item === '货号') {
rowTable['productNo'] = e[item]
} else if (item === '条码') {
rowTable['barCode'] = e[item]
} else {
rowTable['safeQty'] = e[item]
}
}
arr.push(rowTable)
})
} catch (e) {
this.$message.warning('文件解析出错!')
}
}
fileReader.readAsBinaryString(_file)
},
在方法中, 可以拿到键值对形式的解析数据, 之后就可以自己去操作了, 方法里的arr是定义操作的数组, 这个可以自己随意去操作. 不过需要注意的是, 在导入数据量过大的时候, 比如3-5W条, 可能会久一些, 这个需要自己去控制了
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标签地址太长导致网络失败的问题就行.