背景
项目前端开发使用了vue框架+Element组件,但是Element中没有已经实现了的时间进度条可以直接使用,为了满足项目展示任务详情剩余时间和进度的需求,我使用Element的Slider等组件自己封装了一个TimeSlider组件。
Element原组件Slider
- 可以滑动
- 可格式化滑点输出信息
效果图及源码如下:
1 | <div class="block"> |
目标样式
- 进度条左右两端有开始时间和结束时间
- 根据开始时间、当前时间和结束时间刷新进度条,即使用当前时间与开始时间的差占任务总时长的占比来更新进度
- 格式化滑点输出:
- 当任务在进行中,显示任务剩余时间
- 当任务已完成,根据完成时间定格进度,滑点显示已完成
- 当任务由于发布者取消、领取者放弃或超时,进度定格在100处,滑点显示任务未完成
编码实现
在
<el-row>
中分3列<el-col>
,分别展示开始时间、进度条和结束时间,并设置好组件props以满足调用时传参所需。所传参数意义为:
- startTime:任务开始时间
- endTime:任务结束时间
- finNum:完成任务的人数(仅当任务为问卷任务时需要)
- missionState:任务当前状态(包括进行中、已完成、未完成即已结束)
- finishTime:任务完成的时间
- orderState:功能类似missionState,用于不同场景
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56<template>
<div>
<el-row type="flex" align="middle">
<el-col v-bind:span="5" style="text-align: center">{{ startTime }}</el-col>
<el-col v-bind:span="14">
<el-slider></el-slider>
</el-col>
<el-col v-bind:span="5" style="text-align: center">{{ endTime }}</el-col>
</el-row>
</div>
</template>
<script>
export default {
name: 'TimeSlider',
data () {
return {}
},
props: {
startTime: {
type: String,
default: ''
},
endTime: {
type: String,
default: ''
},
finNum: {
type: Number,
default: 0
},
missionState: {
type: Number,
default: 0
},
finishTime: {
type: String,
default: ''
},
orderState: {
type: Number,
default: 0
}
}
}
</script>
<style scoped>
</style>根据开始时间和结束时间计算时间进度条每次跳动的距离
下面得到的结果为任务时长,使用100除以上述结果并向下取整即可得到时间进度条每次跳动的距离
1
2
3
4
5
6
7
8
9
10timeDiff (sTime, eTime) {
let startTime = new Date(sTime)
let endTime = new Date(eTime)
let leftHour = 0
if (endTime.getTime() > startTime.getTime()) {
let msDiff = endTime.getTime() - startTime.getTime()
leftHour = Math.floor(msDiff / (1000 * 3600))
}
return leftHour
}计算当前时间距离开始时间过去了多久,并根据2计算的结果设置当前任务进度
以下根据任务当前的状态设置进度值,若为进行中任务,则继续计算并持续更新进度,若为已完成则定格进度值,若为未完成(取消或超时),则进度值为100
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27passTime (startTime, endTime, finishTime) {
let sTime = new Date(startTime)
let nowTime = Date.now()
let eTime = new Date(endTime)
if (this.finNum !== 0 || this.orderState === 1) {
let finTime = new Date(finishTime)
let passHour = 0
if (finTime.getTime() > sTime.getTime()) {
let msDiff = finTime.getTime() - sTime.getTime()
passHour = Math.ceil(msDiff / (1000 * 3600))
}
return passHour * (100.0 / this.timeDiff(startTime, endTime))
} else if ((this.missionState > 2 && this.finNum === 0) || this.orderState === 2) {
return 100
}
if (nowTime >= eTime.getTime()) {
return 100
}
let passHour = 0
if (nowTime > sTime.getTime()) {
let msDiff = nowTime - sTime.getTime()
passHour = Math.ceil(msDiff / (1000 * 3600))
}
return passHour * (100.0 / this.timeDiff(startTime, endTime))
}根据需求格式化滑点的输出
根据任务状态和需求设置滑点数据的显示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28formatTooltip () {
if ((this.finNum !== 0 && this.missionState === 2) || this.orderState === 1) {
return '已完成'
} else if (this.missionState > 2 && this.finNum === 0 && this.orderState !== 2) {
return '任务已结束或已取消(未完成)'
} else if (this.orderState === 2) {
return '任务已结束或已放弃(未完成)'
}
let currTime = Date.now()
let eTime = new Date(this.endTime.toString())
let left = '任务未完成,已结束'
if (eTime.getTime() > currTime) {
let msDiff = eTime.getTime() - currTime
// compute day left
let leftDay = Math.floor(msDiff / (1000 * 24 * 60 * 60))
// hours left after computing day left
let leaveForHour = msDiff % (1000 * 24 * 60 * 60)
// compute hour left
let leftHour = Math.floor(leaveForHour / (1000 * 60 * 60))
let leaveForMinute = leaveForHour % (1000 * 3600)
let leftMinute = Math.floor(leaveForMinute / (1000 * 60))
let leaveForSecond = leaveForMinute % (1000 * 60)
let leftSecond = Math.round(leaveForSecond / 1000)
left = '剩余' + leftDay + '天' + leftHour + '时' + leftMinute + '分' + leftSecond + '秒'
}
return left
}进度条不可人为改动,所以需要添加
disable
完整代码及效果图
1 | <template> |
在页面主键中引用上述TimeSlider并传相应参数即可使用该组件:
1 | <template> |
效果图如下: