<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>