最简实时拦截数字输入应使用oninput事件配合正则/[^0-9]/g替换非法字符,兼容IE10+;增强版需支持小数和负号,须分步处理非法字符、多余负号及小数点个数。
用 oninput + 正则替换实现最简实时拦截
直接在 <input> 上绑定 oninput 事件,用正则把非数字字符当场抹掉,不等失焦、不靠 onblur,用户根本输不进去。这是最轻量、兼容性最好(ie10+)的做法。
注意别用 onkeypress 或 onkeydown —— 它们无法拦截粘贴、拖入、IME 输入等行为,且 keyCode 判断在中文输入法下极易失效。
-
oninput触发时机晚于输入完成(含粘贴),但早于焦点离开,能覆盖所有输入途径 - 正则推荐用
/[^0-9]/g,匹配所有非数字字符;/\D/g看似简洁,但会误删小数点、负号(如果需要支持) - 必须用
value = value.replace(...)赋值,不能只调用replace不赋值
<input type="text" id="numInput" placeholder="请输入数字"><script>
document.getElementById('numInput').oninput = function() {
this.value = this.value.replace(/[^0-9]/g, '');
};
</script>
支持小数和负号的增强版写法
纯整数太局限,实际常需保留一位小数或允许负数。此时正则要更精细,且需防重复小数点、开头多个负号等问题。
核心思路:先允许「-」在开头、「.」在中间,再用逻辑控制小数点个数和位置,不能全靠正则一步到位。
- 先用
/[^0-9.-]/g拦截非法字符 - 再用
split('.').length > 2控制最多一个点 - 负号只允许出现在首位:
value[0] !== '-' && value.includes('-')就要删掉其他负号 - Layui 表单中若启用了
lay-verify="number",它只在提交时校验,不影响实时输入逻辑
document.getElementById('numInput').oninput = function() {
let v = this.value;
// 先清除非数字、点、负号
v = v.replace(/[^0-9.-]/g, '');
// 多个负号只留开头一个
if (v.indexOf('-') !== -1 && v.indexOf('-') !== 0) {
v = v.replace(/-/g, '').padStart(v.length, '-');
}
// 多个小数点只留第一个
const dots = v.split('.');
if (dots.length > 2) {
v = dots[0] + '.' + dots.slice(1).join('');
}
this.value = v;
};
避免 Layui 的 form.render() 干扰输入状态
如果页面里调用了 form.render()(比如动态增删表单项后),Layui 会重置所有 input 的原生事件绑定,导致你写的 oninput 失效。
这不是 bug,是 Layui 对表单控件的接管机制。解决方案不是放弃 form.render(),而是把它和你的事件绑定解耦。
- 不要在
form.render()后再单独绑定oninput—— 它会被覆盖 - 改用事件委托:绑定到父容器(如
form或.layui-form),监听input事件并过滤目标元素 - 或者,在每次
form.render()后,立刻重新执行一遍你的绑定逻辑(加个封装函数) - 更稳妥的是:把输入逻辑抽成函数,统一在
form.on('submit(...)前做最终校验,oninput只做基础过滤
移动端软键盘兼容性要注意什么
安卓微信内置浏览器、部分国产浏览器对 oninput 支持不稳定,有时粘贴后不触发,或中文输入法下拼音上屏瞬间触发多次。
这不是代码问题,是环境限制。临时缓解方案只有两个:
- 加一层
onblur作为兜底:失焦时再执行一次清洗逻辑,确保最终值合规 - 对关键字段(如金额),提交前用
parseFloat(value) || 0再转一次,避免空字符串或非法值进入业务逻辑 - 别依赖
input[type="number"]—— 它在 iOS Safari 上会强制唤出数字键盘,但无法阻止粘贴字母,且样式难统一
真正难处理的是用户长按粘贴带单位的文本(如“123元”),这种场景建议配合后端校验,前端只做尽力而为的体验优化。











