<template>
<div class="progress-box">
<div class="container">
<div class="loading-icon" ></div>
<div class="loading-bar">
<div class="progress" :style="{ width: process + '%'}"></div>
</div>
<div class="loading-text">{{ `${Math.floor(this.current*100)/100}M/${this.total}M` }}</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
total: 20,
current: 0,
timer: null
}
},
methods: {
progressing(period) {
let _self = this;
clearTimeout(this.timer);
this.timer = setTimeout(function timeoutFun() {
if (_self.current >= _self.total) {
clearTimeout(_self.timer);
} else {
let random = Math.random() + 1;
_self.current = random + _self.current > _self.total ? _self.total : random + _self.current;
_self.updateProgress();
let nextPeriod = Math.random() * 30 + 100;
clearTimeout(_self.timer);
_self.timer = setTimeout(timeoutFun, nextPeriod);
}
}, period);
},
updateProgress() {
let percent = this.current / this.total;
let container = document.getElementsByClassName('container')[0];
let icon = document.getElementsByClassName('loading-icon')[0];
let left = container.offsetWidth * percent - 20;
if (left < 0) left = 0;
icon.style.left = `${left}px`;
}
},
computed: {
process() {
return this.current / this.total * 100;
}
},
mounted() {
window.onresize = this.updateProgress;
},
created() {
this.progressing(100);
}
}
</script>
<style lang="sass" scoped>
.progress-box
min-width: 300px
max-width: 900px
padding: 0 50px
margin: 100px auto
.container
position: relative
.loading-icon
position: absolute
left: 0px
top: -26px
width: 20px
height: 20px
border-radius: 50%
background-color: #000
transition: .25s
.loading-bar
width: 100%
height: 10px
background-color: #d6e6f7
border-radius: 20px
.progress
width: 0px
height: 100%
background-color: #007fff
border-radius: 20px
transition: .25s
.loading-text
margin-top: 6px
text-align: right
font-size: 14px
color: #ccc
</style>
注意點:
(1)模擬數據加載的速度,涉及到了每次加載的間隔隨機,在setTimeout中的callback使用聲明函數(而不用匿名方法),用於方法內遞歸調用。
(2)寬度的百分比是參照其父元素,但是translateX(translateY)的百分比是參照其本身的寬高,因此這裏採用left屬性(以父級的寬度爲基準)來動態設置icon的位置;
(3)由於icon自身也有寬度,因此移動的距離要減去自身的寬度,這裏用js計算更爲方便,但要考慮到加載過程中若瀏覽器窗口大小改變而導致icon錯誤的問題,因此要增加監聽窗口變化的事件,重新計算icon的位置
(4)利用transition可使進度條位置的改變更爲平滑