问题描述
我们日常做项目,特别是后台管理系统,常常需要导出excel文件。实现方式有三种
方式一(后端处理)
后端直接返回一个excel表格地址,前端点击下载即可。不过这种方式,会导致后端的excel越存越多,造成冗余。不过如果是固定模板表格内容不会变得情况下,这种方式还是不错的。当然解决方案就是后端写一个定时器,每隔一段时间清理一次
看情况使用,如果是固定的表格,一两年都不更换的excel表格用这种方式倒是也可以的。后端固定写死只把这个固定的表格传递给前端,这样的话,也能用
方式二(后端处理)
后端返回一个blob流文件,这样的话,是一次性的流文件,使用一次就没了,就不会造成后端excel越存越多。这种方式挺好
目前这种方式使用的会稍微多一些点
方式三(前端处理)
前端保存需要导出的表格内容,然后下载并使用excel插件轮子,就可以导出了。不过众所周知,前端只是拿到数据,并展示数据的。如果表格内容比较多,或者用户对于前端速度有要求的话,或者主管老大不希望我们在项目中下载安装太多的轮子从而导致最终打包文件过大的话,这种方式就不太好
不推荐
流文件导出步骤
流文件导出注意事项
需要加responseType: 'blob',否则文件会损坏
注意,excel流文件一定要在请求的时候加上响应类型字段,也就是:responseType: 'blob'或者,responseType: 'arraybuffer' ,否则下载出来的excel文件就会损坏,就会打不开。损坏文件如下图所示:
ArrayBuffer和Blob一样,都是二进制数据的容器,而ArrayBuffer相比更为底层一些,他可以去操作去修改这些二进制值,以此同时,二者之间也是可以相互转换的。导出excel用哪个都行的
如何加responseType: 'blob'
我使用的axios发请求,所以需要在请求的时候加上,又因为给axios做了二次封装,使用了请求拦截器和相应拦截器,以及包装函数导出,(请求拦截器和相应拦截器就不写了,主要看包装函数导出)代码写法是这样的:
export default (method, url, data = null, headers = 'application/json;charset=UTF-8', responseType = null) => {
if (method == "post") {
return http({
method: 'post',
url: rootUrl + url,
// url: url,
data: data,
headers: {
'Content-Type': headers,
},
responseType: responseType // 相应类型如果有的话,就用接口中的,如果没有就默认为null
});
} else if (method == "get") {
return http({
method: 'get',
url: rootUrl + url,
// url: url,
params: data,
headers: {
'Content-Type': headers
},
responseType: responseType // 相应类型如果有的话,就用接口中的,如果没有就默认为null
});
} else {
return;
}
}
这里包装的return出去的http函数接收的参数除了method请求方式、url请求地址、data请求参数、以及请求头(编码方式制定UTF-8)之外,再多一个相应类型responseType,默认为null,所以只需要在写接口的时候,最后一个位置参数附上就行了。
查看我们加上去的responseType
我们打印一下相应拦截器的结果就能看到了
http.interceptors.response.use((res) => {
console.log('响应拦截器查看',res); // 打印这个结果就能看到responseType了
return res.data
}, (error) => {
return Promise.reject(error);
})
没加的responseType为null
加上就是blob或者ArrayBuffer
步骤一
在导出的接口加上声明接收参数 最后一个参数就是指定类型为blob或者arraybuffer
export const export = (params) => http("get", `api/export`, params, 'application/json; charset=UTF-8', 'arraybuffer')
步骤二
假设我们点击按钮导出excel表格
// 导出按钮的回调函数中
async outExcelData() {
// 准备参数
let params = xxx
const res = await this.$api.export(params);
const blob = new Blob([res]); // 把得到的结果用流对象转一下
var a = document.createElement("a"); //创建一个<a></a>标签
a.href = URL.createObjectURL(blob); // 将流文件写入a标签的href属性值
a.download = "基础工艺数据.xlsx"; //设置文件名
a.style.display = "none"; // 障眼法藏起来a标签
document.body.appendChild(a); // 将a标签追加到文档对象中
a.click(); // 模拟点击了a标签,会触发a标签的href的读取,浏览器就会自动下载了
a.remove(); // 一次性的,用完就删除a标签
},
总结
注意,必须要声明流文件且得到的结果用流文件转一下,这样的话,就不会出现excel文件损坏、或者乱码的情况。