前端实现下载进度条百分比实时显示
工作中经常会遇到下载文件的需求,如果一般的大小还可以很快的下载下来,但是如果报表类的文件,一般都会比较大,这时候就会等很久才可以下载完成,但是用户可能并不知道目前下载的情况,可能会以为没有下载成功,频繁点击,所以网上搜索了一下,整理了目前比较常用的显示下载进度的方式,目前是使用VUE elementUi Axios 实现的
一般调用接口有两种下载方式:
第一种,直接访问**[*服务器的文件地址,自动下载文件
第二种 ,服务器返回blob文件流,再对文件流进行处理和下载。
一般小文件后端会使用第一种方式,大文件会采取文件流的方式进行下载
这个是我公司的下载接口,可以看到已经是很慢的了,体验并不好,所以加一个能实时显示进度的功能,这样用户也能有感知。
具体步骤:
1.封装一个调用接口的公用方法:
// 新建一个index.js文件或写在comments.js公共文件中
import axios from "axios"; // 没有下载的话可以直接装一个 npm i axios
export function downLoadAll(params) {
let downProgress = {};
let uniSign = new Date().getTime() ""; // 可能会连续点击下载多个文件,这里用时间戳来区分每一次下载的文件
const url = process.env.VUE_APP_BASE_API params.url; // 我的项目是需要本地配置不同环境的地址,如果能够直接拿到,就可以不用拼接
axios({
url: url,
method: "post", // 调用类型依据后端接口调用为准
data: params.data, // 接口入参 post:data;get:params
responseType: "blob", // 响应类型
headers: { Authorization: "Bearer " getToken() }, //这里需要拼接token 否则会无法请求,我这里是调用getToken方法拿到的,以前就配好了
onDownloadProgress(progress) { // onDownloadProgress 监听下载进度的方法
downProgress = Math.round((100 * progress.loaded) / progress.total); // progress对象中的loaded表示已经下载的数量,total表示总数量,这里计算出百分比。注意这里一定需要后端接口返回 Content-Length,没有的话是拿不到的
store.commit("downFiles/SET_PROGRESS", {
path: uniSign,
progress: downProgress,
}); // 将此次下载的文件名和下载进度组成对象再用vuex状态管理
},
})
.then((res) => {
// 文件流传输完成后,开启文件下载
if (params.downLoadName) {
jsFileDownLoad(res.data, params.downLoadName ".xlsx"); // jsFileDownLoad是用来下载文件流的,下载插件:npm i js-file-download,import引入:import jsFileDownLoad from 'js-file-download'
} else {
jsFileDownLoad(res.data, "下载文件.xlsx"); // 如果没有文件名字,就给个默认文件名
}
})
.catch((e) => {
console.log(e)
params.that.$message.error("该文件无法下载"); // 报错处理.params.that由于拿不到this,所以传入的
});
}
一定要有Content-Length!!!
2.vuex封装
const state = {
progressList: [], // 文件下载进度列表
};
const mutations = {
SET_PROGRESS: (state, progressObj) => {
// 修改进度列表
if (state.progressList.length) {
// 如果进度列表存在
if (state.progressList.find((item) => item.path == progressObj.path)) {
// 前面说的path时间戳是唯一存在的,所以如果在进度列表中找到当前的进度对象
state.progressList.find(
(item) => item.path == progressObj.path
).progress = progressObj.progress; // 改变当前进度对象的progress
}
} else {
state.progressList.push(progressObj); // 当前进度列表为空,没有下载任务,直接将该进度对象添加到进度数组内
}
},
DEL_PROGRESS: (state, props) => {
state.progressList.splice(
state.progressList.findIndex((item) => item.path == props),
1
); // 删除进度列表中的进度对象
},
};
export default {
namespaced: true, // 一定要加
state,
mutations,
};
// 这里是使用module 子模块,需要在根文件的state里面引入使用
import downFiles from "./modules/downFiles";
moudle:{
downFiles
}
3.生成一个mixins文件,因为许多地方要用,所以直接使用混入比较方便,而使用混入比较方便
// 用到了element的消息提示Notification 组件
import { mapState } from "vuex";
export const mixins = {
computed: {
...mapState({
progressList: (state) => state.downFiles.progressList,
}),
},
data() {
return {
notify: {}, // 用来维护下载文件进度弹框对象
};
},
watch: {
// 监听进度列表
progressList: {
handler(n) {
let data = JSON.parse(JSON.stringify(n));
data.forEach((item) => {
const domList = [...document.getElementsByClassName(item.path)];
if (domList.find((i) => i.className === item.path)) {
// 如果页面已经有该进度对象的弹框,则更新它的进度progress
if (item.progress)
domList.find((i) => i.className === item.path).innerHTML =
item.progress "%";
if (item.progress === null) {
// 此处容错处理,如果后端传输文件流报错,删除当前进度对象
this.$store.commit("downFiles/DEL_PROGRESS", item.path);
this.$notify.error({ title: "错误", message: "文件下载失败!" });
}
} else {
// 如果页面中没有该进度对象所对应的弹框,页面新建弹框,并在notify中加入该弹框对象,属性名为该进度对象的path(上文可知path是唯一的),属性值为$notify(element ui中的通知组件)弹框对象
this.notify[item.path] = this.$notify.success({
dangerouslyUseHTMLString: true,
customClass: "progress-notify",
message: `<p style="width: 150px;line-height: 13px;">文件下载进度<span class="${item.path}" style="float: right">${item.progress}%</span></p>`, // 显示下载百分比,类名为进度对象的path(便于后面更新进度百分比)
showClose: true,
duration: 0,
});
}
if (item.progress === 100) {
// 如果下载进度到了100%,关闭该弹框,并删除notify中维护的弹框对象
// this.notify[item.path].close()
// 上面的close()事件是异步的,直接delete this.notify[item.path]会报错,利用setTimeout,将该操作加入异步队列
setTimeout(() => {
delete this.notify[item.path];
}, 1000);
this.$store.commit("downFiles/DEL_PROGRESS", item.path); // 删除caseInformation中state的progressList中的进度对象
}
});
},
deep: true,
},
},
};
4.页面调用
import { downLoadAll } from 导入方法
confirmExport() { // 点击确认下载
try {
const data = {
参数: 参数值,
};
const downLoadName = "文件下载"
const params = {
url: url,
data,
downLoadName,
that: this,
};
downLoadAll(params);
} catch (error) {
console.log(error);
}
},
完成,效果如下:
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgbbacc
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01