103 lines
2.2 KiB
Vue
103 lines
2.2 KiB
Vue
<template>
|
|
<span>
|
|
{{ lastTime | format }}
|
|
</span>
|
|
</template>
|
|
|
|
<script>
|
|
|
|
function fixedZero(val) {
|
|
return val * 1 < 10 ? `0${val}` : val;
|
|
}
|
|
|
|
export default {
|
|
name: "CountDown",
|
|
props: {
|
|
format: {
|
|
type: Function,
|
|
default: undefined
|
|
},
|
|
target: {
|
|
type: [Date, Number],
|
|
required: true,
|
|
},
|
|
onEnd: {
|
|
type: Function,
|
|
default: () => {
|
|
}
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
dateTime: '0',
|
|
originTargetTime: 0,
|
|
lastTime: 0,
|
|
timer: 0,
|
|
interval: 1000
|
|
}
|
|
},
|
|
filters: {
|
|
format(time) {
|
|
const hours = 60 * 60 * 1000;
|
|
const minutes = 60 * 1000;
|
|
|
|
const h = Math.floor(time / hours);
|
|
const m = Math.floor((time - h * hours) / minutes);
|
|
const s = Math.floor((time - h * hours - m * minutes) / 1000);
|
|
return `${fixedZero(h)}:${fixedZero(m)}:${fixedZero(s)}`
|
|
}
|
|
},
|
|
created() {
|
|
this.initTime()
|
|
this.tick()
|
|
},
|
|
methods: {
|
|
initTime() {
|
|
let lastTime = 0;
|
|
let targetTime = 0;
|
|
this.originTargetTime = this.target
|
|
try {
|
|
if (Object.prototype.toString.call(this.target) === '[object Date]') {
|
|
targetTime = this.target
|
|
} else {
|
|
targetTime = new Date(this.target).getTime()
|
|
}
|
|
} catch (e) {
|
|
throw new Error('invalid target prop')
|
|
}
|
|
|
|
lastTime = targetTime - new Date().getTime();
|
|
|
|
this.lastTime = lastTime < 0 ? 0 : lastTime
|
|
},
|
|
tick() {
|
|
const {onEnd} = this
|
|
|
|
this.timer = setTimeout(() => {
|
|
if (this.lastTime < this.interval) {
|
|
clearTimeout(this.timer)
|
|
this.lastTime = 0
|
|
if (typeof onEnd === 'function') {
|
|
onEnd();
|
|
}
|
|
} else {
|
|
this.lastTime -= this.interval
|
|
this.tick()
|
|
}
|
|
}, this.interval)
|
|
}
|
|
},
|
|
beforeUpdate () {
|
|
if (this.originTargetTime !== this.target) {
|
|
this.initTime()
|
|
}
|
|
},
|
|
beforeDestroy() {
|
|
clearTimeout(this.timer)
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
|
|
</style> |