首页 > 解决方案 > 反应 onClick 在 Firefox 或 Safari 中不起作用

问题描述

我有一个Button组件onClickMain. 单击时,应调用该onClickButton函数,如果满足所有条件,则应调用该函数startCountdown

在 Chrome 中一切正常,但在 Firefox 或 Safari 中,事件永远不会到达下面的 if 块,因此Countdown.tsx永远不会渲染组件:

// Main.tsx

else if (eventName !== "" && fullDate && futureDateParsed - now > 0) {
      startCountdown(eventName, fullDate, now, futureDateParsed);
    }

提前感谢任何研究它的人。

在这里演示:https ://countdown-timer-seven.vercel.app/

// Button.tsx

import React from "react";
import styled from "styled-components";
interface ButtonColorProps {
  bgColor?: string;
}

interface ButtonProps extends ButtonColorProps {
  text: string;
  onClick: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
}

const ButtonStyles = styled.button<ButtonColorProps>`
  margin-top: 32px;
  border: none;
  border-radius: 6px;
  padding: 8px 16px;
  font-size: 1.5rem;
  background-color: ${(props) => props.bgColor || "green"};
  color: white;
  cursor: pointer;
`;

const Button: React.FC<ButtonProps> = ({
  text,
  onClick,
  bgColor,
}): JSX.Element => {
  return (
    <>
      <ButtonStyles onClick={onClick} bgColor={bgColor}>
        {text}
      </ButtonStyles>
    </>
  );
};

export default Button;
// Main.tsx

import React, { useState } from "react";
import Input from "./Input";
import Button from "./Button";
import HeaderH1 from "./HeaderH1";
import styled from "styled-components";

const MainStyles = styled.div`
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;
  padding: 64px 16px;
  height: 50%;

  @media screen and (min-width: 1024px) {
    padding-top: 128px;
    padding-bottom: 128px;
  }

  input[name="countdown-title"] {
    height: 40px;
    width: 100%;
    max-width: 280px;
    margin-bottom: 32px;
    font-size: 1.5rem;
  }

  input[name="countdown-to-day"],
  input[name="countdown-to-month"],
  input[name="countdown-to-year"] {
    font-size: 1.5rem;
  }
`;

const InputContainerStyles = styled.div`
  display: grid;
  grid-template-columns: repeat(3, minmax(40px, 74px));
  grid-template-rows: 60px;
  grid-gap: 32px;
`;

const ErrorStyles = styled.p`
  display: inline-block;
  position: relative;
  color: lightgrey;
`;

const CountDownNameErrorStyles = styled(ErrorStyles)`
  bottom: 20px;
`;

const DateErrorStyles = styled(ErrorStyles)`
  top: 20px;
  width: 100%;
  max-width: 280px;
  text-align: center;
`;

interface MainProps {
  startCountdown: Function;
}

const Main: React.FC<MainProps> = ({ startCountdown }): JSX.Element => {
  const [eventName, setEventName] = useState<string>("");
  const [dayInput, setDayInput] = useState<number | null>(null);
  const [monthInput, setMonthInput] = useState<number | null>(null);
  const [yearInput, setYearInput] = useState<number | null>(null);
  const [eventNameError, setEventNameError] = useState<string | null>(null);
  const [dateError, setDateError] = useState<string | null>(null);

  const onHandleEventName = (getEventName: string): void => {
    setEventName(getEventName);
  };

  const onHandleDayInput = (getDayInput: string): void => {
    const day = parseInt(getDayInput);
    if (typeof day === "number" && day < 32) {
      console.log(`is number, ${day}`);
      setDayInput(day);
    }
  };

  const onHandleMonthInput = (getMonthInput: string): void => {
    const month = parseInt(getMonthInput);
    if (typeof month === "number" && month < 13) {
      console.log(`is number, ${month}`);
      setMonthInput(month);
    }
  };

  const onHandleYearInput = (getYearInput: string): void => {
    const year = parseInt(getYearInput);
    const thisYear = new Date().getFullYear();
    if (typeof year === "number" && (year > thisYear || year === thisYear)) {
      console.log(`is number, ${year}`);
      console.log(thisYear);
      setYearInput(year);
    }
  };

  const onClickButton = (
    event: React.MouseEvent<HTMLButtonElement, MouseEvent>
  ) => {
    const fullDate = `${monthInput}-${dayInput}-${yearInput}`;
    const now = Date.now();
    const futureDateParsed = Date.parse(fullDate);

    if (eventName === "") {
      setEventNameError("Please enter a title for your countdown.");
    }

    if (
      dayInput === null ||
      monthInput === null ||
      yearInput === null ||
      futureDateParsed - now <= 0
    ) {
      setDateError(
        "Please enter a future date with the correct format DD-MM-YYYY"
      );
    } else if (eventName !== "" && fullDate && futureDateParsed - now > 0) {
      startCountdown(eventName, fullDate, now, futureDateParsed);
    }
  };

  return (
    <MainStyles>
      <HeaderH1 fontSize="2rem">Set your countdown</HeaderH1>
      {eventNameError && (
        <CountDownNameErrorStyles>{eventNameError}</CountDownNameErrorStyles>
      )}
      <Input
        onHandleEventName={onHandleEventName}
        eventName={eventName}
        type="text"
        placeholder="Name your countdown"
        name="countdown-title"
      />
      <InputContainerStyles>
        <Input
          onHandleEventName={onHandleMonthInput}
          dateNumber={monthInput}
          type="text"
          placeholder="MM"
          name="countdown-to-month"
          maxLength={2}
        />
        <Input
          onHandleEventName={onHandleDayInput}
          dateNumber={dayInput}
          type="text"
          placeholder="DD"
          name="countdown-to-day"
          maxLength={2}
        />
        <Input
          onHandleEventName={onHandleYearInput}
          dateNumber={yearInput}
          type="text"
          placeholder="YYYY"
          name="countdown-to-year"
          maxLength={4}
        />
      </InputContainerStyles>
      {dateError && <DateErrorStyles>{dateError}</DateErrorStyles>}
      <Button text="START" onClick={onClickButton} />
    </MainStyles>
  );
};

export default Main;
// App.tsx

import React, { useState } from "react";
import Main from "./components/Main";
import Countdown from "./components/Countdown";
import "./assets/styles/typography.css";
import styled from "styled-components";
import starsBg from "./assets/images/bg-stars.svg";
import hillsBg from "./assets/images/pattern-hills.svg";

const AppStyles = styled.div`
  background: url(${hillsBg}) no-repeat center bottom,
    url(${starsBg}) no-repeat center top,
    linear-gradient(#1e1e2a, #1f1d2a, #211d2b, #231d2b);
  background-size: 100%, cover;
  height: 100vh;
  font-family: "Inter", sans-serif;
`;

const App: React.FC = (): JSX.Element => {
  const [eventName, setEventName] = useState<string>("");
  const [hasEvent, setHasEvent] = useState<boolean>(false);
  const [countdownDays, setCountdownDays] = useState<number | null>(null);
  const [countdownHours, setCountdownHours] = useState<number | null>(null);
  const [countdownMinutes, setCountdownMinutes] = useState<number | null>(null);
  const [countdownSeconds, setCountdownSeconds] = useState<number | null>(null);

  const startCountdown = (eventName: string, fullDate: string): void => {
    setHasEvent(true);
    setInterval(() => {
      const now = Date.now();
      const futureDateParsed = Date.parse(fullDate);

      const difference = Math.abs(futureDateParsed - now);
      const days = Math.floor(difference / (1000 * 60 * 60 * 24));
      const hours = Math.floor(
        (difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
      );
      const minutes = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60));
      const seconds = Math.floor((difference % (1000 * 60)) / 1000);

      setEventName(eventName);
      setCountdownDays(days);
      setCountdownHours(hours);
      setCountdownMinutes(minutes);
      setCountdownSeconds(seconds);
    }, 1000);
  };

  return (
    <AppStyles className="App">
      {hasEvent ? (
        <Countdown
          title={eventName}
          days={countdownDays}
          hours={countdownHours}
          minutes={countdownMinutes}
          seconds={countdownSeconds}
        />
      ) : (
        <Main startCountdown={startCountdown} />
      )}
    </AppStyles>
  );
};

export default App;

标签: reactjstypescriptfirefoxsafari

解决方案


主要问题是您使用Input组件的方式:

<Input
  onHandleEventName={onHandleEventName}
  eventName={eventName}
  type="text"
  placeholder="Name your countdown"
  name="countdown-title"
/>

我不确定确切用途是onHandleEventName什么或您的Input组件是什么样的,但我认为您想onChange改用:

<Input
  onChange={(e) => onHandleMonthInput(e.target.value)}
  // ... Other props
/>

另请注意,我传递e.target.value的不仅仅是event我们想知道用户为每个输入填写的当前值。


所以基本上发生的是你没有检索输入中的文本,所以你的条件总是会失败,导致Countdown永远不会显示。


推荐阅读