使用Vue3编写倒计时Hook

分析

hook本质上是一个函数,返回需要的数据,且使用在setup函数中.很容易构想出函数应该是这样

const time = useCountdown();

且该函数需要返回倒计时的剩余天数,时分秒。像这样 01天13小时20分20秒。

另外倒计时的结束时间应该是可变的作为参数传进去

编写

完整代码

import { onBeforeUnmount, reactive } from 'vue';


/**
 *
 * 倒计时hook
 *
 * @example
 * const time = useCountdown({
 *   endDate: '2021-12-31 12:30:00',
 * })
 *
 * @param {Object} arg
 * @param {String|Number} arg.endDate - 结束时间。例如 '2021-12-31 12:30:00'或一个毫秒时间戳 1640930400000
 * @returns {{s: string, d: string, h: string, m: string}} - 对象,其中 d:天数 h:时 m:分 s:秒
 */

function useCountdown(arg) {
  const { endDate: ed } = arg;

  let intervalId = null;
  let timeoutId = null;

  const value = reactive({
    d: '00',
    h: '00',
    m: '00',
    s: '00',
  });

  //获取当前时间
  const now = new Date().getTime();

  //设置截止时间
  const end = new Date(ed).getTime();

  //时间差
  let leftTime = end - now;

  const callback = (minus = 1000) => {

    leftTime -= minus;

    if (leftTime >= 0) {
      value.d = padZero(Math.floor(leftTime / 1000 / 60 / 60 / 24));
      value.h = padZero(Math.floor(leftTime / 1000 / 60 / 60 % 24));
      value.m = padZero(Math.floor(leftTime / 1000 / 60 % 60));
      value.s = padZero(Math.floor(leftTime / 1000 % 60));
    } else {
      clearInterval(intervalId);
    }
  };

  // 计算是否是整秒
  const remain = leftTime % 1000;

  if (remain === 0) {
    intervalId = setInterval(callback, 1000);
  } else {
    timeoutId = setTimeout(() => {
      callback(remain);
      intervalId = setInterval(callback, 1000);
    }, remain);
  }

  onBeforeUnmount(() => {
    clearInterval(intervalId);
    clearTimeout(timeoutId);
  });

  return value;
}

export default useCountdown;


const padZero = (str) => {
  return str.toString().length === 1 ? `0${str}` : str;
};

使用

setup中使用

import useCountdown from '@/hooks/useCountdown'

export default{
  setup(){
    const time =  useCountdown({
        endDate:'2021-12-31 12:00:00'
    })
    return {
      time
    }
  }
}