javascript - 如何使用keyevents在输入字段中防止负数和超过一定限制的数字,并让用户在可用数字之间循环?
问题描述
我有一个名为TimePickerComponent的可重用组件,我用它来显示一个输入字段,用户可以在其中输入小时和分钟。我有一些箭头出现在悬停上,让用户在几小时内向上或向下,以及另一个箭头在分钟内(我在附件中放了截图)
对于分钟,如果用户使用向上箭头到达 59 并再次单击,则下一个数字将是 00。而如果用户使用向下箭头并到达数字 00,则下一个值将是 60。所以基本上它循环。小时数也是如此,但从 0 到 24。使用箭头和 onClick 事件,一切正常。
问题是,当我不使用箭头并且用户使用keyDown事件时,数字变为负无穷大,而当用户使用keyUp事件时,数字变为无穷大。所以我想知道是否应该创建一个可以覆盖此输入字段行为的函数,如果是,如何?我尝试了这些事件,但没有成功。这是我使用箭头但不使用 keyPress 事件的初始代码,我还在附件中添加了页面部分的屏幕截图:
function TimePickerComponent({ hours, setHours, minutes, setMinutes }) {
// INTERVAL STATES ARROWS
const [showIntervalFirstHoursArrow, setShowIntervalFirstHoursArrow] =
useState(false);
const [showIntervalFirstMinutesArrow, setShowIntervalFirstMinutesArrow] =
useState(false);
// INCREMENTS/DECREMENTS HOURS INTERVALS
const incrementFirstHour = () => {
setHours((prevHours) => {
// if there is nothing
if (!prevHours || +prevHours >= 24) {
return '0';
} else {
return String(+prevHours + 1);
}
});
};
const decrementFirstHours = () => {
setHours((prevHours) => {
// if there is nothing
if (!prevHours) {
return '0';
} else if (+prevHours <= 0) {
return '24';
} else {
const currentHours = String(+prevHours - 1);
if (currentHours.length === 1) {
return '0' + currentHours;
}
return currentHours;
}
});
};
// INCREMENTS/DECREMENTS MINUTES INTERVALS
const incrementFirstMinutes = () => {
setMinutes((prevMinutes) => {
// if there is nothing
if (!prevMinutes || +prevMinutes >= 59) {
return '00';
} else {
const currentMinute = String(+prevMinutes + 1);
if (currentMinute.length === 1) {
return '0' + currentMinute;
}
return currentMinute;
}
});
};
const decrementFirstMinutes = () => {
setMinutes((prevMinutes) => {
// if there is nothing
if (!prevMinutes) {
return '00';
} else if (+prevMinutes <= 0) {
return '59';
} else {
const currentMinute = String(+prevMinutes - 1);
if (currentMinute.length === 1) {
return '0' + currentMinute;
}
return currentMinute;
}
});
};
return (
<Inputs>
<Container>
<Selection
onMouseEnter={() => setShowIntervalFirstHoursArrow(true)}
onMouseLeave={() => setShowIntervalFirstHoursArrow(false)}
>
{showIntervalFirstHoursArrow && (
<p className="icon" onClick={incrementFirstHour}>
<IoIosArrowUp />
</p>
)}
<SquareInput
type="number"
onChange={(e) => setHours(e.target.value)}
value={hours}
/>
{showIntervalFirstHoursArrow && (
<p className="icon" onClick={decrementFirstHours}>
<IoIosArrowDown />
</p>
)}
</Selection>
<p>:</p>
<Selection
onMouseEnter={() => setShowIntervalFirstMinutesArrow(true)}
onMouseLeave={() => setShowIntervalFirstMinutesArrow(false)}
>
{showIntervalFirstMinutesArrow && (
<p className="icon" onClick={incrementFirstMinutes}>
<IoIosArrowUp />
</p>
)}
<SquareInput
min="0"
type="number"
onChange={(e) => {
if (e.target.value.split('').length > 2) return;
// if(e.target.value == 0) return;
if (+e.target.value > 60) {
return;
// setMinutes('0');
} else if (+e.target.value < 0) {
setMinutes('60');
} else {
setMinutes(e.target.value);
}
}}
value={minutes}
/>
{showIntervalFirstMinutesArrow && (
<p className="icon" onClick={decrementFirstMinutes}>
<IoIosArrowDown />
</p>
)}
</Selection>
</Container>
</Inputs>
);
}
// STYLES
const Inputs = styled.div`
display: flex;
align-items: center;
p {
font-size: 0.8em;
text-align: center;
}
`;
const Container = styled.div`
border: 1px solid #c5c5c5;
border-radius: 10px;
height: 40px;
margin: 0 5px;
display: flex;
align-items: center;
`;
const Selection = styled.div`
.icon {
font-size: 1.2em;
padding: 10px;
cursor: pointer;
}
`;
const SquareInput = styled.input`
width: 50px;
border: none;
outline: none;
font-size: 1.1em;
text-align: center;
::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* /* Firefox */
/* input[type=number] {
-moz-appearance: textfield;
} */
`;
export default TimePickerComponent;
解决方案
您可以尝试更改方法并统一处理值的增加/减少的函数和负责处理格式的函数。
这将在值更改后触发,无论是在箭头单击还是键盘事件上:
function TimePickerComponent({ hours, setHours, minutes, setMinutes }) {
// INTERVAL STATES ARROWS
const [showIntervalFirstHoursArrow, setShowIntervalFirstHoursArrow] =
useState(false);
const [showIntervalFirstMinutesArrow, setShowIntervalFirstMinutesArrow] =
useState(false);
// INCREMENTS/DECREMENTS HOURS INTERVALS
const incrementDecrementHours = (isIncrement) => {
setHours((prevHours) => (isIncrement ? prevHours + 1 : prevHours - 1));
};
const handleFirstHoursChange = () => {
setHours((prevHours) => {
if (!prevHours || prevHours >= 24) {
return '0';
} else if (prevHours <= 0) {
return '24';
} else if (prevHours.length === 1) {
return '0' + prevHours;
} else {
return prevHours;
}
});
};
// INCREMENTS/DECREMENTS MINUTES INTERVALS
const incrementDecrementMinutes = (isIncrement) => {
setMinutes((prevMinutes) =>
isIncrement ? prevMinutes + 1 : prevMinutes - 1
);
};
const handleFirstMinutesChange = () => {
setMinutes((prevMinutes) => {
if (!prevMinutes || prevMinutes >= 59) {
return '00';
} else if (prevMinutes <= 0) {
return '59';
} else if (prevMinutes.length === 1) {
return '0' + prevMinutes;
} else {
return prevMinutes;
}
});
};
return (
<Inputs>
<Container>
<Selection
onMouseEnter={() => setShowIntervalFirstHoursArrow(true)}
onMouseLeave={() => setShowIntervalFirstHoursArrow(false)}
>
{showIntervalFirstHoursArrow && (
<p className='icon' onClick={incrementDecrementHours(true)}>
<IoIosArrowUp />
</p>
)}
<SquareInput
type='number'
onChange={handleFirstHoursChange}
value={hours}
/>
{showIntervalFirstHoursArrow && (
<p className='icon' onClick={incrementDecrementHours(false)}>
<IoIosArrowDown />
</p>
)}
</Selection>
<p>:</p>
<Selection
onMouseEnter={() => setShowIntervalFirstMinutesArrow(true)}
onMouseLeave={() => setShowIntervalFirstMinutesArrow(false)}
>
{showIntervalFirstMinutesArrow && (
<p className='icon' onClick={incrementDecrementMinutes(true)}>
<IoIosArrowUp />
</p>
)}
<SquareInput
min='0'
type='number'
onChange={handleFirstMinutesChange}
value={minutes}
/>
{showIntervalFirstMinutesArrow && (
<p className='icon' onClick={incrementDecrementMinutes(false)}>
<IoIosArrowDown />
</p>
)}
</Selection>
</Container>
</Inputs>
);
}
推荐阅读
- intellij-idea - 如何安全地为 IntelliJ 中的单元测试提供用户凭据?
- outlook - 如何在资源管理器 Outlook 中显示起草邮件?C#
- swiftui - SwiftUI - 向上滚动时将文本移动到标题
- python - Beautifulsoup 中没有任何返回
- javascript - 利用搜索框中输入未反映在 URL 中的 XSS 漏洞
- ubuntu - 使用 ffmpeg 从 wav 文件中完全删除高频
- javascript - React JS 如何将单个函数添加到数字输入箭头?
- excel - 基于单元格值的工作簿名称
- android - SplashScreen API 与 WindowCompat setDecorFitsSystemWindows 清除窗口背景颜色
- javascript - 为什么对象构造函数属性是全局范围的?