CountDown.tsx 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. "use client";
  2. import { useEffect, useState, useRef, useCallback } from "react";
  3. export default function CountDown({
  4. endTime,
  5. boxClassName,
  6. timerClassName,
  7. onCountDownEnd
  8. }: {
  9. endTime: number;
  10. boxClassName?: string;
  11. timerClassName?: string;
  12. onCountDownEnd: () => void;
  13. }) {
  14. const defaultBoxClassName = boxClassName || "flex items-center gap-2 flex-none text-ly-14 text-white";
  15. const defaultTimerClassName = timerClassName || "flex items-center justify-center w-6 h-6 bg-white rounded-xs text-ly-12 font-medium text-black";
  16. const timerRef = useRef<number | null>(null);
  17. const [seconds, setSeconds] = useState(() => {
  18. return Math.max(0, Math.floor((endTime - Date.now()) / 1000));
  19. }); // 倒计时的总秒数
  20. const clearTimer = () => {
  21. if (timerRef.current !== null) {
  22. clearInterval(timerRef.current);
  23. timerRef.current = null;
  24. }
  25. };
  26. const start = useCallback(() => {
  27. if (timerRef.current) return;
  28. timerRef.current = window.setInterval(() => {
  29. setSeconds((prev) => {
  30. if (prev <= 1) {
  31. clearTimer();
  32. onCountDownEnd();
  33. return 0;
  34. }
  35. return prev - 1;
  36. });
  37. }, 1000);
  38. }, [onCountDownEnd]);
  39. const format = (n: number) => {
  40. const h = Math.floor(n / 3600);
  41. const m = Math.floor((n % 3600) / 60);
  42. const s = n % 60;
  43. return {
  44. hour: String(h).padStart(2, "0"),
  45. minute: String(m).padStart(2, "0"),
  46. second: String(s).padStart(2, "0"),
  47. }
  48. };
  49. useEffect(() => {
  50. start();
  51. return () => clearTimer();
  52. }, [start]);
  53. const { hour, minute, second } = format(seconds);
  54. return (
  55. <div className={defaultBoxClassName}>
  56. <span className={defaultTimerClassName}>{hour}</span>
  57. :
  58. <span className={defaultTimerClassName}>{minute}</span>
  59. :
  60. <span className={defaultTimerClassName}>{second}</span>
  61. </div>
  62. );
  63. }