背景:a标签支持直接设置地址,点击下载文件,这种方式在文件较大的情况下,会出现点击之后页面无反应,造成重复点击的问题;
1. 封装组件,依赖element-ui 的button组件,使用a标签做下载功能,
新建DownloadButton.vue文件
<!-- 导出按钮,增加loading样式 -->
<template>
<el-button v-bind="{ ...$attrs, ...$props, ...$refs }"
:loading="btnLoading" @click="exportFile">
<slot>导出</slot>
</el-button>
</template>
<script>
import axios from 'axios'
// 这是转义传递的参数的方法,按照各自项目需求确认是否使用
import qs from 'qs';
export default {
data () {
return {
btnLoading: false
}
},
props: {
// 导出地址
exportUrl: {
type: String,
require: true
},
// 传递参数
params: {
type: Object
},
icon: {
type: String,
default: 'el-icon-download'
},
size: {
type: String,
default: 'mini'
}
},
methods: {
// 导出
exportFile() {
this.btnLoading = true
axios.get(`${this.exportUrl}?${this.qs(this.params)}`, {
responseType: 'blob',
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'Cache-Control': 'no-cache',
'Pragma': 'no-cache'
}
}).then(res => {
// 返回的格式是blob,需要转换后得到后端返回的json数据,然后判断code值
let _this = this
let data = res.data
let fileReader = new FileReader()
fileReader.readAsText(data)
fileReader.onload = function() {
try {
// json解析成功证明是json数据
let jsonData = JSON.parse(this.result)
if (jsonData.code !== 0) {
_this.$message.warning(jsonData.message)
}
_this.btnLoading = false
} catch (err) {
// 否则是文件
_this.downLoadFile(res)
}
}
}).catch(() => {
this.btnLoading = false
});
},
downLoadFile(res) {
let response = res.headers["content-disposition"]
// TODO 这里改成正则获取文件名称
let name = response.split("filename=")[1]
let fileName = decodeURIComponent(name)
// 如果支持微软的文件下载方式(ie10+浏览器)
if (window.navigator.msSaveBlob) {
try {
const blobObject = new Blob([res.data]);
window.navigator.msSaveBlob(blobObject, fileName);
} catch (e) {
console.log(e);
}
} else {
// 其他浏览器
const url = window.URL.createObjectURL(new Blob([res.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
document.body.removeChild(link); // 下载完成移除元素
window.URL.revokeObjectURL(url); // 释放掉blob对象
}
this.btnLoading = false
},
qs(obj) {
return qs.stringify(obj)
}
}
};
</script>
<style lang="scss" scoped>
</style>
2. 使用组件
<!-- 默认导出按钮 RequestUrl为定义的常量地址 post是筛选条件 -->
<download-button :exportUrl="RequestUrl.URLA" :params="post" />
<!-- 其他按钮文字 -->
<download-button :exportUrl="RequestUrl.URLB" :params="post">
详情导出
</download-button>
<!-- 设置其他属性 -->
<download-button :exportUrl="RequestUrl.URLC" :params="post" size="small" icon="el-icon-delete">
列表导出
</download-button>