最稳妥的正整数校验方案是使用oninput事件配合正则/^(?!0)\d*$/,并单独处理paste事件;html原生type="number"需搭配js兜底;避免v-model.number等隐式转换。

oninput 里用 /^[1-9]\d*$/ 匹配正整数最稳妥
这个正则能准确排除 0、01、空字符串和负数,只保留以 1–9 开头、后跟任意个数字(包括零个)的字符串。关键点在于:它不依赖事件时机,也不修改用户正在输入的中间状态。
常见错误是用 /^\d+$/ —— 它会放过 0 和 00;或者用 /^[0-9]+$/,同样无法拦截开头为 0 的非法值(比如 05)。
实操建议:
- 必须搭配
oninput,不是onkeyup或onchange:前者响应所有输入源(键盘、粘贴、语音),后者在中文输入法未上屏时失效 - 别直接赋值
this.value = ''或0:这会打断光标位置、破坏用户体验;应只做“过滤”,即保留合法前缀 - 推荐写法:
oninput="this.value = this.value.replace(/^(?!0)\d*$/g, '$&').replace(/[^0-9]/g, '')",但更安全的是分步校验
type="number" + min="1" + step="1" 是 HTML 原生方案
这是语义最清晰、无障碍支持最好、移动端键盘自动弹出数字键盘的方式。浏览器会原生阻止非数字输入,并限制最小值为 1。
但要注意几个坑:
- 用户仍可手动清空或输入
e、-、.,然后失焦时被浏览器自动修正(不同浏览器行为不一致) - Firefox 允许粘贴
-5或1.5,再失焦才触发校验,此时值已污染 DOM - Vue/React 等框架中若用
v-model或受控组件,需额外监听input事件做二次过滤 - 不能靠 CSS 或
readonly拦截,必须配合 JS 校验兜底
粘贴(paste)场景下 onafterpaste 不可靠,要用 onpaste 阻止默认行为
很多教程还写 onafterpaste,但它在现代浏览器中基本不触发,属于过时 API。真正有效的是监听 onpaste,并在事件中调用 event.preventDefault(),再手动读取剪贴板内容过滤。
使用 Puppeteer + Chrome 将 HTML 渲染为中文 PDF,自动处理图表等待、Tab 展开、动画、测高、白边消除、防分页,适用于看板、报表、网页和交互图表转 PDF。
示例逻辑:
- 监听
onpaste="handlePaste($event)" - 在
handlePaste中event.preventDefault() - 用
event.clipboardData.getData('text')取原始粘贴内容 - 用
/^[1-9]\d*$/.test(pasted)判断,合法才写入this.value
否则用户粘贴 abc123def 或 007,会直接塞进输入框,后续校验已晚。
Vue 场景下慎用 v-model.number 做正整数校验
v-model.number 会把空字符串转成 NaN,把 "01" 转成 1,看似“转数字”了,但丢失了“是否允许前导零”的业务意图。它不拒绝 0,也不报错,只是默默转换。
更危险的是:当绑定数据是 0 时,输入框显示为空;用户输入 5 后,值变成 5;但如果用户删到空,值又变回 NaN,导致表单逻辑断裂。
建议做法:
- 用
v-model绑定字符串,保持类型可控 - 在
@input中调用校验函数,例如:@input="val => model = /^[1-9]\d*$/.test(val) ? val : model" - 配合
:value+@input实现完全受控,避免框架与 DOM 状态错位
真正难的不是写出正则,而是覆盖粘贴、拖拽、IME 输入、屏幕阅读器交互这些边界情况。一个没处理 onpaste 的正整数输入框,在真实用户手里三分钟内就会出问题。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










