用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;

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

相关推荐
一城烟雨_2 小时前
vue3 实现将html内容导出为图片、pdf和word
前端·javascript·vue.js·pdf
树懒的梦想2 小时前
调整vscode的插件安装位置
前端·cursor
低代码布道师4 小时前
第二部分:网页的妆容 —— CSS(下)
前端·css
一纸忘忧4 小时前
成立一周年!开源的本土化中文文档知识库
前端·javascript·github
涵信4 小时前
第九节:性能优化高频题-首屏加载优化策略
前端·vue.js·性能优化
前端小巷子4 小时前
CSS单位完全指南
前端·css
SunTecTec5 小时前
Flink Docker Application Mode 命令解析 - 修改命令以启用 Web UI
大数据·前端·docker·flink
软件技术NINI5 小时前
html css js网页制作成品——HTML+CSS甜品店网页设计(4页)附源码
javascript·css·html
涵信5 小时前
第十一节:性能优化高频题-响应式数据深度监听问题
javascript·vue.js·性能优化
codingandsleeping6 小时前
Express入门
javascript·后端·node.js