<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可使进度条位置的改变更为平滑