reactjs - 反应 onClick 在 Firefox 或 Safari 中不起作用
问题描述
我有一个Button
组件onClick
从Main
. 单击时,应调用该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;
解决方案
主要问题是您使用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
永远不会显示。
推荐阅读
- c# - ASP.NET Core 3.1 区域在某些方法上返回 404,但在索引一上没有
- java - 通过工厂方法在类路径资源 Bean 实例化中定义的“springSecurityFilterChain”失败;
- sql-server - 通过循环查找最大长度
- android - 根据 Xamarin 中的平台切换 TabbedPage 视图
- javascript - 如何获取表单数据?
- javascript - 如何在 jQuery 中获取 DOM 元素
- c# - C# - Jint 通用方法
- encryption - 使用 N、c、e 进行 CTF RSA 解密
- java - mongo java驱动比shell慢(15倍)
- spring - 在 websphere 8.5.5 中部署时 Spring Web 服务中的链接错误