如何防止 HTML number 输入框中输入无效数字(如 --99)

本文介绍在 html `` 中拦截非法数值输入(如重复符号 `--99`、`+-5` 等)的可靠方案,重点解决 `parsefloat()` 无法捕获中间态输入、`event.preventdefault()` 在 `change` 事件中失效等问题,并提供基于 `input` 事件 + 正则校验 + 值回滚的完整实现。

HTML 原生 虽支持基础数值约束(如 min/max、箭头调节),但对输入过程中的非法字符序列(如 --99、-+5、12.3.4、e10)缺乏实时拦截能力。关键问题在于:

  • change 事件仅在失焦或回车后触发,此时浏览器可能已自动修正或清空值,event.preventDefault() 无效;
  • parseFloat("--99") 返回 -99,无法识别语法错误;
  • Number.isNaN() 对空字符串、"-"、"--" 等中间态输入返回 true,但此时用户仍在输入,需保留编辑状态。

✅ 正确解法:监听 input 事件 + 正则预判 + 值快照回滚

// TypeScript 示例(Angular)
private lastValidValue: string = "";

onQuantityInput(event: Event) {
  const input = event.target as HTMLInputElement;
  const rawValue = input.value;

  // 允许的格式:空字符串、单个 '-'、合法负数/正数(含小数点)
  // 正则说明:
  // ^-?        → 可选开头负号
  // (\d*\.?\d*) → 整数或小数(允许 . 开头如 ".5",由 parseFloat 兼容)
  // $          → 结尾
  const isValidFormat = /^-?(\d*\.?\d*)$/.test(rawValue);

  // 额外排除纯 "-" 或 "--" 等无效前缀
  if (!isValidFormat || rawValue === "-" || rawValue === "") {
    // 恢复上一个有效值(首次输入时为空)
    input.value = this.lastValidValue;
    return;
  }

  // 尝试解析为数字,排除 NaN 和 Infinity
  const num = parseFloat(rawValue);
  if (isNaN(num) || !isFinite(num)) {
    input.value = this.lastValidValue;
    return;
  }

  // 更新最后有效值快照
  this.lastValidValue = rawValue;
}

onQuantityBlur(event: Event) {
  const input = event.target as HTMLInputElement;
  // 失焦时强制标准化:空值设为 0,或按业务逻辑处理
  if (input.value === "") {
    input.value = "0";
    this.lastValidValue = "0";
  }
}

⚠️ 注意事项:

  • 不要用 pattern + type="text" 替代:虽然 支持正则,但会失去原生 number 输入体验(如移动端数字键盘、滚轮调节、step 属性等),且 pattern 仅在表单提交时校验,无法实时响应。
  • 避免依赖 change 事件:它不适用于实时防错,仅适合最终确认逻辑。
  • 区分 input 和 keydown:keydown 可拦截按键但难以处理粘贴、拖拽等操作;input 是更全面的输入捕获时机。
  • 兼容性提示:该方案在所有现代浏览器中稳定运行,无需 polyfill。

? 进阶建议:若需更严格的格式控制(如禁止 .5 而只允许 0.5),可增强正则为 /^-?(?:\d+(?:\.\d+)?|\.\d+)$/,并结合 min/max 属性做二次约束。

通过快照 + 实时正则 + input 事件三者协同,即可在保留原生 number 输入优势的同时,彻底杜绝 --99 等非法输入,确保数据层始终接收语义正确的数值。