React数字输入框正则优化:兼容Tab/Enter等功能键的方案
数字输入框拦截非数字输入的问题解决
问题背景
我在表单里创建数字输入框时,发现type="number"的输入框居然还能输入文本,这会破坏后续的计算逻辑。于是我加了onKeyDown事件来拦截非数字输入,代码如下:
const inputPattern = /[0-9]|[,.]/; const onKeyDown = (e) => { if (!inputPattern.test(e.key.toString())) { e.preventDefault(); } };
React组件中的输入框代码:
<input type="number" name="derp" onKeyDown={onKeyDown} />
当前方案的问题
这个方法确实能阻止文本输入,但把Tab切换输入框、Enter提交表单这些必要操作也给拦截了,非常影响使用。
已尝试的无效方案
- 使用input的
pattern属性:还是允许输入文本 - 改用
text类型输入框:计算前要手动转类型,太麻烦 - 使用
inputmode="decimal":只改了移动端键盘样式,还是能输入文本
解决方案
方案一:修改逻辑,放行控制键
直接判断并放行Tab、Enter、Backspace这些必要的控制键,再拦截非数字输入:
const onKeyDown = (e) => { // 先放行控制键和常用组合键(如复制粘贴) const allowedKeys = ['Tab', 'Enter', 'Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']; const allowedComboKeys = ['c', 'v', 'x', 'a']; if (allowedKeys.includes(e.key) || (e.ctrlKey && allowedComboKeys.includes(e.key))) { return; } // 只允许数字、小数点、逗号 const inputPattern = /[0-9,.]/; if (!inputPattern.test(e.key)) { e.preventDefault(); } };
方案二:用input事件实时过滤
input事件能覆盖粘贴、拖拽输入等场景,实时清理非法内容,还不会拦截控制键:
const handleInput = (e) => { // 保留数字和唯一的小数点/逗号 const cleanedValue = e.target.value .replace(/[^0-9,.]/g, '') // 移除所有非数字、非标点的字符 .replace(/([,.]).*\1/g, '$1'); // 只保留第一个小数点/逗号 e.target.value = cleanedValue; };
绑定到输入框:
<input type="number" name="derp" onInput={handleInput} />
方案三:提交时校验(适合实时性要求低的场景)
利用type="number"的原生校验,配合onInvalid在提交时提示错误,虽然不能实时阻止输入,但实现简单:
<input type="number" name="derp" required onInvalid={(e) => { e.target.setCustomValidity('请输入有效的数字'); }} onInput={(e) => { e.target.setCustomValidity(''); // 输入有效内容时清除错误提示 }} />
内容的提问来源于stack exchange,提问作者martijn
相关产品推荐
相关产品推荐

