当前位置:首页 > VUE

vue实现倒计时组件

2026-02-09 19:21:31VUE

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>

优化建议

  1. 使用 Web Worker 处理长时间倒计时,避免主线程阻塞
  2. 添加时区处理,确保目标时间计算准确
  3. 实现格式化函数支持更多自定义格式
  4. 添加多语言支持
  5. 使用 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>

vue实现倒计时组件

标签: 倒计时组件
分享给朋友:

相关文章

vue实现组件拖放

vue实现组件拖放

Vue 实现组件拖放的方法 使用 HTML5 原生拖放 API HTML5 提供了原生的拖放 API,可以通过 draggable 属性、dragstart、dragend、dragover 和 dr…

vue实现倒计时

vue实现倒计时

Vue 实现倒计时的方法 使用 setInterval 实现基础倒计时 通过 Vue 的 data 定义倒计时时间,使用 setInterval 进行倒计时操作,并在组件销毁时清除定时器。 <…

vue组件的实现

vue组件的实现

Vue 组件的实现方式 Vue 组件可以通过多种方式实现,主要包括单文件组件(SFC)、全局注册和局部注册。以下是常见的实现方法: 单文件组件(SFC) 单文件组件是 Vue 最推荐的组件化开发方式…

vue如何实现目录组件

vue如何实现目录组件

实现目录组件的基本思路 在Vue中实现目录组件通常需要结合页面内容的结构化数据(如标题层级),通过动态渲染生成可交互的目录。核心步骤包括提取标题、生成目录结构、实现滚动联动等。 提取标题信息 通过…

vue radio组件实现

vue radio组件实现

Vue Radio 组件实现 在 Vue 中实现 Radio 组件可以通过原生 HTML 的 <input type="radio"> 结合 Vue 的响应式特性来完成。以下是几种常见的实…

vue实现水印组件

vue实现水印组件

Vue 水印组件的实现方法 使用Canvas绘制水印 在Vue组件中通过Canvas动态生成水印图案,将其作为背景添加到目标元素上。 <template> <div ref=…