背景
接口请求时,为了提高用户体验需要展示进度条,包括加载时间和进度。但有时候加载的接口不止一个,又无法得知具体的时间,这时候模拟一个假进度条更为方便。
思路
参考的 nprogress 代码,将内部的进度暴露出来,便于模拟假的时间。 this.$emit(‘progress’, n)
实现
部分代码如下:
<template>
<el-progress :percentage="percentage" :show-text="false" :class="progressClass" v-bind="$attrs" v-on="$listeners" :key="reRenderNum"></el-progress>
</template>
<script>
export default {
name: 'progress-bar',
props: {
progressClass: {
type: String,
default: ''
}
},
data() {
return {
status: 0,
speed: 200,
minimum: 0.08,
reRenderNum: 1, // 避免 status由 1-> 0 时,导致进度条倒退。这里直接重新渲染
resetStatus: true // 避免 status 赋值为 0 时,直接改变进度条样式,需等待再次start进度条才会置空
}
},
computed: {
percentage() {
return this.status * 100
}
},
methods: {
// 外部调用使用,当无需使用假的进度条,直接设置 百分比
setStatus(n) {
this.status = n
},
// 外部调用使用
start() {
if (this.resetStatus) {
this.status = 0
this.resetStatus = false
this.reRenderNum++
this.progress(0)
}
const that = this
const work = function() {
setTimeout(function() {
if (that.resetStatus) return
that.mockIncrease()
work()
}, that.speed)
}
work()
},
// 外部调用使用
done(force) {
if (force || this.status) {
this.mockIncrease(0.3 + 0.5 * Math.random())
this.progress(1)
}
},
// 向外部发送假的进度
progress(n) {
this.status = this.clamp(n, this.minimum, 1)
// 当 status 为 1 时,进度条停止
if (this.status === 1) {
this.resetStatus = true
}
this.$emit('progress', n)
},
mockIncrease(amount) {
let n = this.status
// 如果直接调用 mockIncrease,那么会初始化 start
if (!n) {
this.start()
} else if (n > 1) {
return
} else {
if (typeof amount !== 'number') {
if (n >= 0 && n < 0.2) {
amount = 0.1
} else if (n >= 0.2 && n < 0.5) {
amount = 0.04
} else if (n >= 0.5 && n < 0.8) {
amount = 0.02
} else if (n >= 0.8 && n < 0.99) {
amount = 0.005
} else {
amount = 0
}
}
}
n = this.clamp(n + amount, 0, 0.994)
this.progress(n)
},
// 保持进度 n 处于指定的状态(不会过小,也不会超出一定范围)
clamp(n, min, max) {
if (n < min) return min
if (n > max) return max
return n
}
}
}
</script>
具体使用:
<progress-bar ref="progressBar" :show-text="false" @progress="progress"></progress-bar>
// 开始进度条
this.$refs.progressBar.start()
// 进度条模拟时间
progress(data) {
this.mockLeftText(data)
this.$emit('progress', data)
}
// 结束进度条
this.$refs.progressBar.done(true)
// 模拟剩余时间
mockLeftText(data) {
this.leftPercent = Math.round(data * 100)
this.leftTime = Math.round(this.fakeTotalTime * (1 - data)) // fakeTotalTime 可以给个假的总的时间,例如10s
}
大致效果:
https://ricostacruz.com/nprogress/