type="number" 拦不住 e、-、+ 和小数点,因其原生设计支持科学计数法、负数和小数等合法数值格式,仅在提交或调用 reportvalidity() 时校验,不拦截输入过程。

type="number" 为什么拦不住 e、-、+ 和小数点
因为浏览器原生 type="number" 的设计目标是支持所有合法数值格式:科学计数法(1e3)、负数(-5)、小数(3.14)都算“数字”。它只在表单提交或调用 reportValidity() 时做语义校验,不干预输入过程。用户粘贴 2e1、输入 -abc 或 ..5,DOM 中的 value 可能暂时保留这些内容,valueAsNumber 则直接返回 NaN。
onkeypress 拦非数字键最直接但有兼容陷阱
用 onkeypress 拦 ASCII 48–57(0–9)是最轻量的键盘拦截方式,但它不处理粘贴、拖放、右键菜单输入等绕过路径:
-
event.charCode在现代 Chrome/Firefox 中已废弃,推荐改用event.key或event.code -
event.key === 'e'或event.key === '-'需显式判断,不能只靠/[\d]/正则(它匹配不到e) - 移动端软键盘触发的
keypress行为不稳定,iOS Safari 基本不触发
示例写法:
<input type="number" onkeypress="if (!/^[0-9]$/.test(event.key)) event.preventDefault()">
input 事件 + 正则清洗才是可靠兜底
oninput 是唯一能覆盖键盘输入、粘贴、拖放、剪贴板修改的事件,必须配合正则实时清理:
- 要纯整数:用
/[^0-9]/g替换全部非数字字符(注意不是/\D/g,后者会误删全角数字) - 允许带符号或小数点?别用
/[^0-9.-]/g——它允许多个小数点,应改用更严谨的/^-?\d*\.?\d*$/校验后替换 - 清空后光标会跳到开头,需手动维护
selectionStart;否则用户退格时体验断裂 - 避免无限循环:清洗前比对
oldValue === newValue,相同就跳过赋值
简版可用:
<input type="number" oninput="this.value = this.value.replace(/[^0-9]/g, '')">
移动端和兼容性必须单独处理
在 iOS Safari、微信内置浏览器里,type="number" 的 min/max/step 常失效,上下箭头消失,甚至回退成文本框。此时硬靠属性没用:
- 改用
type="text"+inputmode="decimal"(iOS/Android 会弹出带小数点的数字键盘) - 把
step="1"的整数逻辑挪到 JS 里:提交前检查parseInt(value) === parseFloat(value) - 禁用原生上下箭头:CSS 加
appearance: none; -webkit-appearance: none; - 后端绝不能信任前端传来的
value字符串,必须用parseFloat()或Number()转换并校验范围
真正麻烦的从来不是怎么写那行正则,而是你得同时应付桌面端的键盘事件、移动端的粘贴劫持、Safari 的 valueAsNumber 严格模式,以及用户关掉 JS 后的裸奔表单。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











