vue实现倒计时组件
Vue 倒计时组件实现
方法一:基础倒计时(基于 setInterval)
创建 Countdown.vue 文件,使用 setInterval 实现倒计时逻辑:
<template>
<div>{{ formattedTime }}</div>
</template>
<script>
export default {
props: {
targetTime: {
type: [Date, Number, String],
required: true
},
format: {
type: String,
default: 'HH:mm:ss'
}
},
data() {
return {
remainingTime: 0,
timer: null
}
},
computed: {
formattedTime() {
const hours = Math.floor(this.remainingTime / 3600)
const minutes = Math.floor((this.remainingTime % 3600) / 60)
const seconds = this.remainingTime % 60
return this.format
.replace('HH', hours.toString().padStart(2, '0'))
.replace('mm', minutes.toString().padStart(2, '0'))
.replace('ss', seconds.toString().padStart(2, '0'))
}
},
mounted() {
this.startCountdown()
},
beforeDestroy() {
this.clearTimer()
},
methods: {
startCountdown() {
this.calculateRemainingTime()
this.timer = setInterval(() => {
this.calculateRemainingTime()
if (this.remainingTime <= 0) {
this.clearTimer()
this.$emit('end')
}
}, 1000)
},
calculateRemainingTime() {
const target = new Date(this.targetTime).getTime()
const now = Date.now()
this.remainingTime = Math.max(0, Math.floor((target - now) / 1000))
},
clearTimer() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
}
}
}
</script>
方法二:使用 requestAnimationFrame(更高精度)
适用于需要更高精度的场景:
<template>
<div>{{ formattedTime }}</div>
</template>
<script>
export default {
props: {
duration: {
type: Number,
required: true
}
},
data() {
return {
startTime: null,
remainingTime: this.duration,
animationFrame: null
}
},
computed: {
formattedTime() {
const ms = this.remainingTime
const seconds = Math.floor(ms / 1000) % 60
const minutes = Math.floor(ms / (1000 * 60)) % 60
const hours = Math.floor(ms / (1000 * 60 * 60))
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`
}
},
mounted() {
this.startCountdown()
},
beforeDestroy() {
this.stopCountdown()
},
methods: {
startCountdown() {
this.startTime = performance.now()
this.animationFrame = requestAnimationFrame(this.updateCountdown)
},
updateCountdown(timestamp) {
const elapsed = timestamp - this.startTime
this.remainingTime = Math.max(0, this.duration - elapsed)
if (this.remainingTime > 0) {
this.animationFrame = requestAnimationFrame(this.updateCountdown)
} else {
this.$emit('end')
}
},
stopCountdown() {
if (this.animationFrame) {
cancelAnimationFrame(this.animationFrame)
}
}
}
}
</script>
方法三:带暂停/继续功能的倒计时
扩展基础版本,增加控制功能:
<template>
<div>
<div>{{ formattedTime }}</div>
<button @click="toggle">{{ isRunning ? '暂停' : '继续' }}</button>
</div>
</template>
<script>
export default {
props: {
seconds: {
type: Number,
default: 60
}
},
data() {
return {
remainingTime: this.seconds,
isRunning: false,
timer: null,
lastUpdate: null
}
},
computed: {
formattedTime() {
const minutes = Math.floor(this.remainingTime / 60)
const seconds = this.remainingTime % 60
return `${minutes}:${seconds.toString().padStart(2, '0')}`
}
},
mounted() {
this.start()
},
beforeDestroy() {
this.stop()
},
methods: {
start() {
this.isRunning = true
this.lastUpdate = Date.now()
this.timer = setInterval(() => {
const now = Date.now()
const diff = Math.floor((now - this.lastUpdate) / 1000)
this.lastUpdate = now
this.remainingTime = Math.max(0, this.remainingTime - diff)
if (this.remainingTime <= 0) {
this.stop()
this.$emit('end')
}
}, 1000)
},
stop() {
this.isRunning = false
clearInterval(this.timer)
},
toggle() {
if (this.isRunning) {
this.stop()
} else {
this.start()
}
}
}
}
</script>
优化建议
- 使用 Web Worker 处理长时间倒计时,避免主线程阻塞
- 添加时区处理,确保目标时间计算准确
- 实现格式化函数支持更多自定义格式
- 添加多语言支持
- 使用 CSS 动画增强视觉效果
组件使用示例
<template>
<Countdown
:target-time="targetDate"
format="HH:mm:ss"
@end="handleCountdownEnd"
/>
</template>
<script>
import Countdown from './Countdown.vue'
export default {
components: { Countdown },
data() {
return {
targetDate: new Date(Date.now() + 3600 * 1000) // 1小时后
}
},
methods: {
handleCountdownEnd() {
console.log('倒计时结束')
}
}
}
</script>






