如何在 React 中阻止输入框中输入连字符(-)及其他非数字字符

本文介绍在 react 中使用受控组件实现纯数字输入的正确方法,重点解决 `input type="number"` 允许输入连字符“-”的问题,并提供兼容性好、体验佳的纯文本+正则过滤方案。

在 React 中,直接使用 虽然语义清晰,但存在一个常见陷阱:浏览器允许用户输入负号(-)甚至字母 e(科学计数法),且无法通过 onKeyPress 或 onInput 完全拦截——尤其在 macOS Safari 或部分 Android 键盘上,连字符可能在 onChange 触发前已短暂显示或导致值异常

因此,推荐采用 type="text" + inputMode="numeric" + 受控输入 + 正则过滤 的组合方案,兼顾兼容性、可访问性和用户体验。

✅ 推荐实现(支持全平台,禁止 -、.、e、空格等一切非数字字符)

import { useState, useCallback } from 'react';

function NumberInput() {
  const [value, setValue] = useState('');

  const handleChange = useCallback((evt: React.ChangeEvent) => {
    // 仅保留纯数字字符(0–9),删除所有其他字符(含 -、.、e、空格、字母等)
    const cleaned = evt.target.value.replace(/[^0-9]/g, '');
    setValue(cleaned);
  }, []);

  return (
    
  );
}

export default NumberInput;

? 关键说明

  • inputMode="nu

    meric":向浏览器声明期望输入数字,多数移动端会优先调出数字键盘(比 type="number" 更可靠);
  • pattern="[0-9]*":配合 HTML5 表单验证,在提交时提供基础校验提示(不影响实时过滤);
  • 正则 /[^0-9]/g:精准匹配并移除所有非 ASCII 数字字符,彻底杜绝 -、+、.、e、E、中文数字、符号等干扰;
  • 使用 useCallback 避免 onChange 回调频繁重建,提升性能;
  • aria-label 和语义化属性确保无障碍支持。

⚠️ 注意事项

  • ❌ 不要依赖 type="number" 的原生行为来“保证数字”——它不阻止 - 输入,也无法防止粘贴非法内容(如 "123abc-456");
  • ❌ 避免使用 event.target.value = newValue 手动赋值(如原代码所示),这会破坏 React 受控组件一致性,可能导致状态与 DOM 不同步;
  • ✅ 若需支持小数,应改用更严谨逻辑(如允许最多一个 .,且不能在开头/结尾),但本例聚焦「纯整数」场景;
  • ✅ 如需限制位数(如最多 6 位),可在 cleaned 后追加 cleaned.slice(0, 6)。

通过该方案,你将获得一个真正只接受 0–9 的健壮数字输入框,彻底规避连字符及其他特殊字符的干扰,同时保持良好的跨端体验与可维护性。