Vue文件下载进度条
需求场景:
-
大文件压缩过后依旧很大,接口返回response速度过慢,页面没有任何显示,体验太差。 -
需要在浏览器显示正在加载中的状态优化显示,提高用户体验
实现原理:
-
使用onDownloadProgress方法API获取进度及文件大小等数据 -
mixin混入实现监听进度条进度 -
vuex修改进度条进度
优化过程:
使用onDownloadProgress封装一个下载文件的方法
downFileProgress: function (url, params, headers, blenderApiUrl, callback, uniSign) {
return axios({
url: url,
params: params,
method: 'get',
responseType: 'blob',
baseURL: blenderApiUrl,
headers: headers,
onDownloadProgress (progress) {
callback(progress, uniSign)
}
})
}
在下载文件的地方,使用封装的方法downFileProgress
downOrgFile (row) {
let uniSign = `${new Date().getTime()} ` // 可能会连续点击下载多个文件,这里用时间戳来区分每一次下载的文件
const url = `${this.$api.LifeInsuranceScenario2DownFile}/${row.account_name}/${row.task_id}`
const baseUrl = this.iframeData.blenderApiUrl
this.$http.downFileProgress(url, {}, this.headers, baseUrl, this.callBackProgress, uniSign).then(res => {
if (!res) {
this.$sweetAlert.errorWithTimer('文件下载失败!')
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([res.data]), '中间项下载.zip')
} else {
let url = window.URL.createObjectURL(new Blob([res.data]))
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', 'xxx.zip')
document.body.appendChild(link)
link.click()
link.remove()
}
})
},
callBackProgress (progress, uniSign) {
let total = progress.srcElement.getResponseHeader('Real-Content-Length')
// progress对象中的loaded表示已经下载的数量,total表示总数量,这里计算出百分比
let downProgress = Math.floor((progress.loaded / total) * 100)
// 将此次下载的文件名和下载进度组成对象再用vuex状态管理
this.$store.commit('SET_PROGRESS', { path: uniSign, progress: downProgress })
}
创建component同等级mixin文件夹,文件夹创建index.js
import { mapState } from 'vuex'
export const mixins = {
computed: {
...mapState({
progressList: state => state.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('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('DEL_PROGRESS', item.path) // 删除caseInformation中state的progressList中的进度对象
}
})
},
deep: true
}
}
}
下载方法的组件引入mixin
import { mixins } from '../mixin/index'
export default {
mixins: [mixins],
......
}
Vuex配置进度条
const state = {
progressList: []
}
export default state
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) // 删除进度列表中的进度对象
},
CHANGE_SETTING: (state, { key, value }) => {
// eslint-disable-next-line no-prototype-builtins
if (state.hasOwnProperty(key)) {
state[key] = value
}
}
}
export default mutations
export const getProgressList = state => state.progressList
export const changeSetting = function ({ commit }, data) {
commit('CHANGE_SETTING', data)
}
export const setprogress = function ({ commit }, data) {
commit('SET_PROGRESS', data)
}
export const delprogress = function ({ commit }, data) {
commit('DEL_PROGRESS', data)
}
最终效果图

文章出自:https://juejin.cn/post/7116396739938451464
作者:高蓓蓓
原文始发于微信公众号(前端24):Vue文件下载进度条
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/51251.html