项目中的一个需求:若当前表单有勾选项,则导出勾选项数据,若无,则导出当前所展示的全部数据。(此文勾选项数据处理不做说明)
vue文件流导出有两种情况,对于后端来说,一种是只传递send,一种是传递并下载send and download。此处讨论的是第二种。
【注意】此处调用后端接口api时,要注意项目整体request请求中对于api的封装格式是怎样的,我目前这个项目算是二开,项目中的拦截器对于request的传递数据类型强行转换成了字符串,那么这个时候,该文件流导出所用api调用就不能写在项目的封装api方法里。必须单独写出来。否则你的文件根本导不出来,下载事件也不会触发。
我使用的是axios。
情况一:
一开始,后端要求参数为{ids: ‘1,2,3,4’}类型格式,ids内容为各勾选项数据的id拼接字符串。
解决:
// idString为id拼接字符串
/*
* process.env.VUE_APP_API_BASE_URL为封装的路径前缀,你也可以直接写url
* 'http://xxx.xxx.com/crm/action/export?ids=' + idString
*/
exportExcel(idString) {
axios({
url: process.env.VUE_APP_API_BASE_URL + '/crm/action/export?ids=' + idString,
method: 'POST',
// 必须blob
responseType: 'blob',
headers: { 'Access-Control-Allow-origin': '*', 'Content-Type': 'application/json; charset=UTF-8', 'Token':JSON.stringify(window.localStorage.getItem('X-Auth-Token'))}
}).then((Res) => {
// 定义一个标签a
const link = document.createElement('a');
// 转换文件流类型 => type: 'application/vnd.ms-excel' 转换为excel文件
const blob = new Blob([Res.data], {
type: 'application/vnd.ms-excel'
});
link.style.display = 'none';
link.href = URL.createObjectURL(blob);
// 导出文件命名 '行动记录.xls'
link.setAttribute('download', '行动记录.xls')
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
}
情况二:后来因为有时候数据太多了,一次传id传了四五十个,后端处理报错,后来采用的是json类型参数:[‘1’,‘2’,‘3’,‘4’,‘5’]
解决:
// 此处data值为json参数
exportExcel(data) {
axios({
url: process.env.VUE_APP_API_BASE_URL + '/crm/action/export',
method: 'POST',
responseType: 'blob',
data,
headers: { 'Access-Control-Allow-origin': '*', 'Content-Type': 'application/json; charset=UTF-8', 'Token':JSON.stringify(window.localStorage.getItem('X-Auth-Token'))}
}).then((Res) => {
const link = document.createElement('a');
const blob = new Blob([Res.data], {
type: 'application/vnd.ms-excel'
});
link.style.display = 'none';
link.href = URL.createObjectURL(blob);
link.setAttribute('download', '行动记录.xls')
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
}
- 注意,此时你的参数如果是上一级方法处理的,那传入到exportExcel()中必须是以data传进来的
- exportExcel(data) {}
- 因为我这边的后端设置此json参数是传到body里面的,前端axios({url,method,data})这种格式是固定的,不能把data随便换成idString或者其他你自己定义的什么值。这个具体要看后端写的接口结构是怎样的,如果params传的,前端可操作性就大一点。
PS: 几个踩雷点:
- 导出不触发:如果检查调用api路径,结构格式都对但还是不触发,那大概率就是我最上面说的封装拦截问题。
- 导出触发,但是文件格式不对:new Blob( [ res.data ] ) , { type: ’ xxx ’ } 这个type里的值设置的不对
- 导出触发格式正确,内容为undefined:文件流生成xlsx数据错误,通过打印检查link.href数据查看路径是否存在,或者axios格式是否正确。
- 导出触发格式正确,内容为[ object,object ]:const blob = new Blob([ res.data ]), { type: ‘xxxx’ } 中,注意打印检查后端传进来的文件流是什么格式的,是放到res里的还是放到res.data里的。基本上如果出现这种情况,其他地方没有错误的话,new Blob 中的res / res.data来回调换下应该就可以了。