用React实现一个秒杀倒计时组件

复制代码
先声明一个补0的函数
复制代码
// 先声明一个补0的函数
function formate(time: number): string {
  return `${time < 10 ? "0" : ""}${time}`;
}
复制代码
定义最终返回的数据结构
复制代码
export interface TimeInfo {
  /** 天 */
  day: number;
  /** 小时 */
  hours: number;
  /** 补零后的小时 */
  hoursStr: string;
  /** 分钟 */
  minutes: number;
  /** 补零后的分 */
  minutesStr: string;
  /** 秒 */
  seconds: number;
  /** 补零后的秒 */
  secondsStr: string;
  /** 毫秒 */
  milliseconds?: number;
  /** 补零后的毫秒 */
  millisecondsStr?: string;
  /** 倒计时状态 pending-初始化状态 runing-进行中 end-已结束 */
  status: "pending" | "runing" | "end";
}
复制代码
工具方法——清除倒计时数据信息:
复制代码
function clearCountdownInfo(showMillisecond = false, status?: TimeInfo["status"]): TimeInfo {
  const timeInfo: TimeInfo = {
    day: 0,
    hours: 0,
    hoursStr: "00",
    minutes: 0,
    minutesStr: "00",
    seconds: 0,
    secondsStr: "00",
    status: status || "end",
  };

  if (showMillisecond) {
    timeInfo.milliseconds = 0;
    timeInfo.millisecondsStr = "0";
  }

  return timeInfo;
}
复制代码
关键工具方法——计算倒计时返回的数据信息:
复制代码
function computeCountdownInfo(
  remainTime: number,
  showMillisecond = false
): TimeInfo {
  // 剩余时间小于说明结束,直接清空
  if (remainTime < 0) {
    return clearCountdownInfo(showMillisecond);
  }

  // 这里用了一个比较笨的方法,一个个进行计算,后续可以优化试试看
  const day = Math.floor(remainTime / (24 * 60 * 60));
  const hours = Math.floor((remainTime / (60 * 60)) % 24);
  const hoursStr = formate(hours);
  const minutes = Math.floor((remainTime / 60) % 60);
  const minutesStr = formate(minutes);
  const seconds = Math.floor(remainTime % 60);
  const secondsStr = formate(seconds);

  // 组合成需要返回的时间信息
  const timeInfo: TimeInfo = {
    day,
    hours,
    hoursStr,
    minutes,
    minutesStr,
    seconds,
    secondsStr,
    status: "runing",
  };

  // 需要显示毫秒逻辑处理
  if (showMillisecond) {
    const milliseconds = Math.floor(remainTime * 1000);
    // 只取首位
    const millisecondsStr = String(milliseconds).slice(-3);
    timeInfo.milliseconds = milliseconds;
    timeInfo.millisecondsStr = millisecondsStr;
  }

  return timeInfo;
}

定义函数:

复制代码
interface CountDownOptions {
  showMillisecond: boolean
  deadlineTime: any
}

function computeRemainTime(deadlineTime: number) {
  // 当前时间
  const nowTime = Date.now();
  // 截止时间 - 当前时间 = 剩余时间
  const remainTime = (deadlineTime - nowTime) / 1000;
  return remainTime;
}
复制代码
核心逻辑 —— useCountdown hook 组件:
复制代码
export const useCountdown = (options: CountDownOptions) => {
  // 首次初始化数据,显示清除的数据
  const [timeInfo, setTimeInfo] = useState<TimeInfo>(
    clearCountdownInfo(options.showMillisecond, "pending")
  );
  useEffect(() => {
    let timer = 0;

    function countdown() {
      const remainTime = computeRemainTime(options.deadlineTime);
      // 剩余时间大于 0 才开始倒计时
      if (remainTime > 0) {
        // 未结束时直接定时下一次在执行判断 countdown
        timer = setTimeout(
          countdown,
          options.showMillisecond ? 100 : 1000 // 毫秒级则修改定时器时间
        );
      }
      const data = computeCountdownInfo(remainTime, options.showMillisecond);
      setTimeInfo(data);
    }

    // 开始倒计时
    countdown();

    return () => {
      // 清除定时器
      timer && clearTimeout(timer);
    };
  }, [options.deadlineTime, options.showMillisecond]);

  return timeInfo;
};

看一下在组件中的应用:

复制代码
import { Layout, Row, Typography } from 'antd';
import React from 'react';
import { useCountdown } from './CountDown';

interface Props {
  name: string;
}

const Guide: React.FC<Props> = (props) => {

  // deadlineTime这个时间在传的时候要比当前的时间往后,要不然效果出不来,这里注意一点
  const {
    day,
    hoursStr,
    minutesStr,
    secondsStr,
  } = useCountdown({showMillisecond: false, deadlineTime: 1743907169000})

  return (
    <Layout>
      <div style={{color: 'red', fontSize: 28, marginBottom: 24}}>
        {day}天:
        {hoursStr}时:
        {minutesStr}分:
        {secondsStr}秒
      </div>
    </Layout>
  );
};

export default Guide;

再来看一下页面的效果吧:

相关推荐
LaughingZhu10 小时前
Product Hunt 每日热榜 | 2026-05-21
前端·人工智能·经验分享·chatgpt·html
怕浪猫10 小时前
Electron 开发实战(一):从零入门核心基础与环境搭建
前端·electron·ai编程
小鹏linux10 小时前
Ubuntu 22.04 部署开源免费具有精美现代web页面的Casdoor账号管理系统
linux·前端·ubuntu·开源·堡垒机
前端若水11 小时前
会话管理:创建、切换、删除对话历史
前端·人工智能·python·react.js
Bigger11 小时前
mini-cc:一个轻量级 AI 编程助手的诞生
前端·ai编程·claude
涵涵(互关)12 小时前
Naive-ui树型选择器只显示根节点
前端·ui·vue
BY组态12 小时前
Ricon组态系统最佳实践:从零开始构建物联网监控平台
前端·物联网·iot·web组态·组态
BY组态12 小时前
Ricon组态系统vs传统组态软件:为什么选择新一代Web组态平台
前端·物联网·iot·web组态·组态
SoaringHeart12 小时前
Flutter进阶:OverlayEntry 插入图层管理器 NOverlayZIndexManager
前端·flutter
放下华子我只抽RuiKe512 小时前
React 从入门到生产(四):自定义 Hook
前端·javascript·人工智能·深度学习·react.js·自然语言处理·前端框架