vue useCountDown

691 阅读1分钟

参考:vant-contrib.gitee.io/vant/#/zh-C…

开发中需要用到倒计时功能,苦于没有引入vant ui库,于是动手写了一个。

介绍

提供倒计时管理能力。

代码演示

基本用法

<span>总时间:{{ current.total }}</span>
<span>剩余天数:{{ current.days }}</span>
<span>剩余小时:{{ current.hours }}</span>
<span>剩余分钟:{{ current.minutes }}</span>
<span>剩余秒数:{{ current.seconds }}</span>
<span>剩余毫秒:{{ current.milliseconds }}</span>
<script lang='ts' setup>
import { toRefs } from 'vue'
import { useCountDown } from '../../hook/use'

const countDown = useCountDown({
  // 倒计时 24 小时
  time: 24 * 60 * 60 * 1000,
  autoStart: true
})

const { current } = toRefs(countDown)
</script>

毫秒级渲染

<script lang='ts' setup>
import { toRefs } from 'vue'
import { useCountDown } from '../../hook/use'

const countDown = useCountDown({
  // 倒计时 24 小时
  time: 24 * 60 * 60 * 1000,
  millisecond: true,
  autoStart: true
})

const { current } = toRefs(countDown)
</script>

API

type CurrentTime = {
  total: number
  days: string
  hours: string
  minutes: string
  seconds: string
  milliseconds: string
};

type CountDown = {
  start: () => void
  pause: () => void
  reset: (totalTime: number, autoStart?: boolean) => void
  current: CurrentTime
};

type UseCountDownOptions = {
  time: number
  autoStart?: boolean
  millisecond?: boolean
  onChange?: (current: CurrentTime) => void
  onFinish?: () => void
};

function useCountDown(options: UseCountDownOptions): CountDown;

源码

import { reactive } from 'vue'

interface CurrentTime {
  total: number
  days: string
  hours: string
  minutes: string
  seconds: string
  milliseconds: string
}

interface CountDown {
  start: () => void
  pause: () => void
  reset: (totalTime: number, autoStart?: boolean) => void
  current: CurrentTime
}

interface UseCountDownOptions {
  time: number
  autoStart?: boolean
  millisecond?: boolean
  onChange?: (current: CurrentTime) => void
  onFinish?: () => void
}
export const useCountDown = (options: UseCountDownOptions): CountDown => {
  let countdownTime: NodeJS.Timeout
  const diff = options.millisecond ? 4 : 1000
  const current = reactive({
    total: 0,
    days: '00',
    hours: '00',
    minutes: '00',
    seconds: '00',
    milliseconds: '00',
  })

  const timeDataFormat = () => {
    if (current.total >= 0) {
      current.days = Math.floor(current.total / (24 * 60 * 60 * 1000))
        .toString()
        .padStart(2, '0')
      current.hours = Math.floor((current.total % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000))
        .toString()
        .padStart(2, '0')
      current.minutes = Math.floor((current.total % (60 * 60 * 1000)) / (60 * 1000))
        .toString()
        .padStart(2, '0')
      current.seconds = Math.floor((current.total % 60000) / 1000)
        .toString()
        .padStart(2, '0')
      current.milliseconds = Math.floor(current.total % 1000)
        .toString()
        .padStart(2, '0')
    }
  }

  const start = () => {
    clearTimeout(countdownTime)
    current.total = current.total - diff
    if (current.total >= 0) {
      timeDataFormat()
      options.onChange?.(current)
      countdownTime = setTimeout(() => {
        start()
      }, diff)
    } else {
      options.onFinish?.()
    }
  }

  const pause = () => {
    clearTimeout(countdownTime)
  }

  const reset = (totalTime: number, autoStart = false) => {
    clearTimeout(countdownTime)
    current.total = totalTime
    timeDataFormat()
    if (autoStart) {
      start()
    }
  }

  reset(options.time, options.autoStart)

  return {
    start,
    pause,
    reset,
    current,
  }
}