一般前端导出表格时,后台会有两种方式返给前端数据:
下面我们主要讲一下第二种方式的使用和一些需要注意的地方:
首先我们先看最终要使用到的的正确结果代码:
1.下面代码是核心的处理方法,此处我封装成了一个工具方法在整个项目中使用
export const exportExcel = (data, fileName = "导出表格.xlsx") => {
let blobObj = new Blob([data], {
type: "application/vnd.ms-excel" });
// for IE
if (window.navigator && window.navigator.msSaveBlob) {
window.navigator.msSaveBlob(blobObj, fileName);
} else {
let blobUrl = window.URL.createObjectURL(blobObj);
const link = document.createElement("a"); // 创建a标签
link.href = blobUrl;
link.download = fileName;
link.click(); // 模拟点击a标签
window.URL.revokeObjectURL(link.href);
}
}
2.下面代码是在导出方法里拿到后台数据后进一步作出判断再去调用上面的核心方法
if (res.data.type == "application/octet-stream") {
exportExcel(res.data, "text.xlsx");
} else {
this.$message.error("导出失败");
}
3.下面代码是axios自己封装的一个请求方法,即request方法,其实就是请求后台接口的
export function exportTodayCity(data) {
return request({
url: '/second/seasonal/exportTodayCity',
method: 'post',
data,
responseType: "blob"
})
}
现在我们分析一下上面三点代码的作用及原因:
先讲一下第一点,首先方法有两个参数,分别是data,fileName,data表示处理二进制流为blob对象的数据,fileName表示下载后文件的名字,这里给了一个默认名字,防止传入的名字为空。第一行代码目的是为了转换成自己所需要的新的Blob对象,下面看一下Blob构造函数的具体解释:
var aBlob = new Blob( array, options );
参数:
然后再说这里的参数意义,data为处理二进制流为blob对象的数据,主要说一下这里的type参数里面的值的意义,目的就是改变MIME类型,使下载的文件后缀名为xls,即为表格文件。注意:(这里要说一下,如果 fileName那里的值只是个字符串名字,没有xls或者xlsx后缀名,则这里必须要写这个 type参数并值为application/vnd.ms-excel
,这样生成的文件默认就是以.xls为后缀名的表格文件了,否则有问题。当然了,如果 fileName那里已经是包含了xls或xlsx这样的后缀名了,则这里的 type参数可写可不写,写了也不会冲突,无非最终下载下的文件后缀名是与你 fileName那里的后缀名保持一致)。
这里如果有人想知道MIME类型都有哪些,请看W3school MIME类型 或 MDN MIME类型
后面的代码中主要做了浏览器兼容,其中msSaveBlob为了兼容IE下载导出,具体意义可查看MDN msSaveBlob
再后面就是使用 createObjectURL 创建一个临时的URL,然后创建一个a标签,模拟点击事件,从而进行下载导出,最后通过 revokeObjectURL释放创建的引用即可。对于这两个API不了解的可自行百度查看,也可以直接在MDN上查看。
第一点讲完了,我们再来看第二点,代码不多,这里主要做了判断处理,目的是为了处理后台导出失败时的情况,因为我们返回拿到的数据会被转换成blob类型,具体原因待会看第三点再说。这里就会出现不管成功还是失败都是blob类型的响应数据,就不能用平时json类型那种用code码来做判断了。这里是通过blob对象里的type字段值来做判断处理的,因为不管失败还是成功,他的blob结构一样,无非是type值不一样,所以就使用这个字段值作为成功与否的判断就行了。成功时type会返回application/octet-stream
,失败时,谷歌和火狐会返回application/json
,IE浏览器会返回application/json; charset=utf-8
,故这里使用成功时的返回值作为成功与否的判断。当然了,这种要保证这个导出接口后台返回的只有这两种type值,不存在其他情况。按理来说,这里也就两种type情况,不会有第三种出现。
再说最后一点,这里主要加一个字段responseType:"blob"
,因为接受的是二进制流,不是json格式数据,所以这里需要设置响应数据为blob对象,一般平时JSON格式请求只需要url,method,data三个参数即可,但这里导出下载一定要加这一行代码,因为使用axios请求时,responseType默认的是json。
额外说一下,刚才上面最后一点讲的设置responseType:"blob"
这个字段值,其实这里也可以设置成responseType:"arraybuffer"
,一样可以正常导出下载。这里就有人问了,那两个有啥区别?我只能简略地告诉你它们的区别:Blob 用于操作二进制文件,ArrayBuffer 用于操作内存。ECMAScript 6 入门里面这样说的:
如果明确知道返回的二进制数据类型,可以把返回类型(responseType)设为arraybuffer;如果不知道,就设为blob
blob 与 arraybuffer的具体详细内容可以参考 ArrayBuffer 对象,Blob 对象
到此,基本上该说的已经说完了,如有没有讲到的地方,可以留言告诉我,看到一定回复,好了,该去上个厕所了。。。
------------------------------------------------2020.08.31更新--------------------------------------------------------
之前说的第二点那里,导出失败的话,返回的是json格式,那里直接输出的提示“导出失败”,如果可能我们需要读取后台返回的信息,那就得考虑从后台返回的字段里读值了,而这里我们默认是以blob格式接收的,所以,我们此时要想办法将blob对象数据转换回json格式后再进一步操作即可。下面就是具体实现代码:
将上面第二点里的this.$message.error("导出失败");
替换为下面的代码即可。
let reader = new FileReader();
reader.readAsText(res.data); // res.data 是接收后台的blob格式数据对象
reader.onload = (e) => {
let res = JSON.parse(e.target.result);
if (res.code == 400) {
this.$message.error(res.msg);
}
};
当然了,具体进行什么操作看自己业务需求进行稍加改动即可。