在项目中遇到后端将excel文件通过文件流的方式返回给前端 前端需要进行下载 实验很久之后实现的方式如下
首先需要知道后端返回文件流的时候 我们需要在请求的时候将responseType的值设置为blob
由于我的项目中的请求是进行过封装的 没有搞清楚怎么添加这个设置 因此我在需要下载的页面单独引入了axios
import axios from 'axios' // 依赖中已经下载过axios了 直接引入即可
以下是实现布局的代码
<div class="download">
<el-date-picker
v-model="time"
type="daterange"
align="right"
unlink-panels
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="pickerOptions"
value-format="yyyy-MM-dd"
size="small"
@change="getTime"
>
</el-date-picker>
<el-button
type="success"
size="small"
@click="download"
icon="el-icon-download"
:disabled="isDownload"
>
导出列表
</el-button>
</div>
以下是data中定义的代码
data(){
return {
isDownload: true, // 下载按钮是否可点击
time: "", // 下载时间
// 时间选择器快捷选项
pickerOptions: {
shortcuts: [
{
text: "最近一周",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit("pick", [start, end]);
},
},
{
text: "最近一个月",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
picker.$emit("pick", [start, end]);
},
},
{
text: "最近三个月",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
picker.$emit("pick", [start, end]);
},
},
],
},
isClick: false, // 是否点击下载按钮
}
}
以下是下载实现功能的代码
// 控制按钮的禁用状态 在日期选择后才允许按钮点击
getTime(val) {
if (val) {
this.isDownload = false;
} else {
this.isDownload = true;
}
},
// 下载
async download() {
// 防止重复点击
if (!this.isClick) {
this.isClick = true;
// 因为需要筛选日期之后再发送请求给后端 这里定义了请求参数 time是组件v-model绑定的值
let params = {
start_time: this.time[0] + " 00:00:00",
end_time: this.time[1] + " 23:59:59",
};
// 不同环境的请求地址不同 我这里是直接从地址栏取的请求地址的前半段,然后拼接后端给的接口地址
let url = window.location.href.split("#")[0];
// 当为开发环境时
if (url.includes("localhost")) {
url = url + "api/admin/exports";
} else {
url = url + "admin/exports";
}
// 发送请求
axios
.request({
url, //请求路径
responseType: "blob",
method: "get",
params,
})
.then((res) => {
//此处有个坑。这里用content保存文件流,最初是content=res,但下载的test.xls里的内容如下图1,
//检查了下才发现,后端对文件流做了一层封装,所以将content指向res.data即可
//另外,流的转储属于浅拷贝,所以此处的content转储仅仅是便于理解,并没有实际作用=_=
const content = res.data; // 这里试试res 不行就用res.data
const blob = new Blob([content]); //构造一个blob对象来处理数据
const fileName = "心愿列表.xlsx"; // 下载的文件名称 可以自定义
//对于<a>标签,只有 Firefox 和 Chrome(内核) 支持 download 属性
//IE10以上支持blob但是依然不支持download
if ("download" in document.createElement("a")) {
//支持a标签download的浏览器
const link = document.createElement("a"); //创建a标签
link.download = fileName; //a标签添加属性
link.style.display = "none";
link.href = URL.createObjectURL(blob);
document.body.appendChild(link);
link.click(); //执行下载
URL.revokeObjectURL(link.href); //释放url
document.body.removeChild(link); //释放标签
} else {
//其他浏览器
navigator.msSaveBlob(blob, fileName);
}
})
.catch((err) => {
console.log(err);
});
} else {
this.$message.warning("请勿重复点击!");
}
},
以下是控制不可重复点击的代码
// 观察数据
watch: {
isClick() {
if (this.isClick) {
let timeID = setTimeout(() => {
this.isClick = false;
clearTimeout(timeID);
}, 5000);
}
},
},
放一张成功下载的截图
结束了~