如何通过keyEvents限制输入框数值范围并实现循环,解决时间选择器键盘输入越界问题
解决方案
你需要给输入框绑定onKeyDown事件拦截默认的上下键行为,同时补全输入校验规则即可,修改后的完整代码如下:
import { useState } from 'react'; import styled from 'styled-components'; import { IoIosArrowUp, IoIosArrowDown } from 'react-icons/io'; 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 (!prevHours || +prevHours >= 24) { return '00'; } else { return String(+prevHours + 1).padStart(2, '0'); } }); }; const decrementFirstHours = () => { setHours((prevHours) => { if (!prevHours) { return '00'; } else if (+prevHours <= 0) { return '24'; } else { return String(+prevHours - 1).padStart(2, '0'); } }); }; // INCREMENTS/DECREMENTS MINUTES INTERVALS const incrementFirstMinutes = () => { setMinutes((prevMinutes) => { if (!prevMinutes || +prevMinutes >= 59) { return '00'; } else { return String(+prevMinutes + 1).padStart(2, '0'); } }); }; const decrementFirstMinutes = () => { setMinutes((prevMinutes) => { if (!prevMinutes) { return '00'; } else if (+prevMinutes <= 0) { return '59'; } else { return String(+prevMinutes - 1).padStart(2, '0'); } }); }; return ( <Inputs> <Container> <Selection onMouseEnter={() => setShowIntervalFirstHoursArrow(true)} onMouseLeave={() => setShowIntervalFirstHoursArrow(false)} > {showIntervalFirstHoursArrow && ( <p className="icon" onClick={incrementFirstHour}> <IoIosArrowUp /> </p> )} <SquareInput type="number" onChange={(e) => { const val = e.target.value if (val.length > 2) return const numVal = +val if (numVal > 24 || numVal < 0) return setHours(val) }} onKeyDown={(e) => { if (e.key === 'ArrowUp') { e.preventDefault() incrementFirstHour() } else if (e.key === 'ArrowDown') { e.preventDefault() decrementFirstHours() } }} onBlur={() => { setHours(prev => { if (!prev) return '00' let num = +prev num = ((num % 25) + 25) % 25 return String(num).padStart(2, '0') }) }} 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) => { const val = e.target.value if (val.length > 2) return const numVal = +val if (numVal >= 60 || numVal < 0) return setMinutes(val) }} onKeyDown={(e) => { if (e.key === 'ArrowUp') { e.preventDefault() incrementFirstMinutes() } else if (e.key === 'ArrowDown') { e.preventDefault() decrementFirstMinutes() } }} onBlur={() => { setMinutes(prev => { if (!prev) return '00' let num = +prev num = ((num % 60) + 60) % 60 return String(num).padStart(2, '0') }) }} 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; } -moz-appearance: textfield; `; export default TimePickerComponent;
修改说明
- 新增
onKeyDown事件拦截上下方向键的默认行为,直接复用已有的增减逻辑,保证键盘调整和箭头点击的循环规则完全一致 - 补全了小时输入框的
onChange校验,限制输入长度最大为2位,同时禁止输入超出0-24范围的数值 - 修正了分钟输入框的校验逻辑:将原判断阈值>60调整为>=60,小于0时返回59而非错误的60
- 优化了增减函数的前导零处理逻辑,统一用
padStart方法补零,代码更简洁 - 新增
onBlur失焦事件,用户主动输入完成离开输入框时,自动补全前导零、修正非法数值,和组件的展示规则对齐 - 补全了火狐浏览器下数字输入框的默认箭头隐藏样式
内容的提问来源于stack exchange,提问作者user14749773
相关产品推荐
相关产品推荐

