只有email、url、number、date、datetime-local、month、week、time这8种type触发浏览器原生验证;其余如tel、search、text不校验,仅影响键盘或需配合required/pattern等属性生效。

原生 input 标签本身不提供“即时校验”逻辑,所谓“即时”是靠组合 HTML5 属性 + 事件监听 + 合理触发时机实现的;盲目加 oninput 或全用 required 反而导致误报、卡顿或校验失效。
哪些 input type 能触发浏览器原生校验?
只有明确语义类型的 input 在提交时才会被浏览器自动校验,且仅限 form 提交瞬间(不是输入时):
-
type="email":检查是否含@和域名结构,但不验证邮箱真实存在 -
type="url":要求以http://或https://开头(部分浏览器宽松) -
type="number":阻止非数字字符输入(但允许粘贴、空值、e符号等边界情况) -
type="date"/time/datetime-local:依赖系统控件选值,空值时校验失败 -
type="text"等通用类型:必须配合required、pattern、minlength才生效
注意:type="tel" 和 type="search" 不触发任何格式校验,只影响移动端键盘唤起。
oninput vs onblur:什么时候该用哪个?
纯靠 oninput 做“实时”反馈,容易在用户未输完时就标红(比如刚敲 1 就提示“金额不能为 1”);只用 onblur 又延迟明显。真实场景应分字段策略处理:
- 金额类(
type="number"):oninput做输入净化(如this.value = this.value.replace(/[^0-9.]/g, '')),onblur做范围校验(min="0"+ JS 判断是否 > 0) - 邮箱类(
type="email"):oninput不跑正则,onblur再执行/^[^\s@]+@[^\s@]+\.[^\s@]+$/ - 必填文本(
type="text"):oninput清除上一次错误态,onblur检查this.value.trim() === ''并标红 - 密码强度类:
oninput动态计算并更新强度条,但不阻断输入;提交前再综合判断
关键点:不要在 oninput 里调用 reportValidity() 或修改样式,那会卡 UI。
动态新增行时,校验逻辑怎么不崩?
表格中每行 input 必须有唯一上下文,否则校验状态错乱、后端收不到全部数据:
- 禁止重复写
name="amount"—— 后端用req.body.amount只能取到最后一行 - 禁止重复写
id="amount"——document.getElementById('amount')永远只返回第一行 - 正确做法:
<tr data-row-id="0"><input name="amount-0" data-field="amount"></tr>,校验结果存进 JS 对象{'0': {amount: 'valid', email: 'invalid'}} - 事件绑定必须用委托:
tbody.addEventListener('input', e => { if (e.target.matches('input[data-field]')) { ... } }),从e.target向上找closest('tr')获取dataset.rowId
这样新增 100 行也不用重新 bind,更不会因异步插入 DOM 未就绪而漏绑。
错误提示放哪才不影响布局又清晰?
绝对定位进 <td> 是最稳方案:
<ul>
<li>不用额外 DOM 结构,避免破坏表格语义和响应式行为</li>
<li>用 <code>position: absolute; right: 4px; top: 50%; transform: translateY(-50%); 紧贴输入框右边缘垂直居中
<td> 设置 <code>position: relative,否则会相对整个页面定位
<span></span> 插在 <input> 后面 —— 宽度变化时容易换行或遮挡光标真正容易被忽略的是:当用户快速切换焦点(Tab 键)时,上一行的错误提示可能还没来得及隐藏,需要统一管理显示/隐藏生命周期,而不是每个 onblur 单独控制。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











