required 属性仅在原生表单提交(如 type="submit" 按钮或回车)时生效,不响应 form.submit() 调用;对 select 生效需首项 value="" 且未选中;空格或零宽字符仍被判定为空;iOS Safari 中 display: none 内的 required 输入框可能无法唤起键盘。

required 属性为什么没反应
加了 required 却不报错、不阻止提交,大概率是表单触发方式错了。它只在原生提交时生效:必须用 <button type="submit"></button> 或回车,不能靠 form.submit() 调用;也不能写在 <div> 或 <code>type="hidden" 上——这些元素压根不参与校验流程。
常见踩坑点:
-
required对<select></select>生效的前提是:首项<option value=""></option>且未选中任何有值的项;如果首项写了selected,浏览器会认为“已选空值”,直接判定失败 - 用户只输空格或零宽字符(比如粘贴来的不可见符号),
.value.trim() === ""仍为true,校验照样拦住 - 移动端 iOS Safari 在
display: none容器里渲染的required输入框,可能无法唤起键盘,导致用户根本输不了
type="email" 和 pattern 正则校验的区别
type="email" 是浏览器内置的轻量格式检查,只验证是否含 @ 和域名结构(如 a@b.c),不保证真实存在;而 pattern 需配合正则表达式做自定义规则,比如手机号 pattern="[0-9]{11}",但注意它只对 type="text"、"tel"、"email" 等少数类型生效。
关键差异:
立即学习“前端免费学习笔记(深入)”;
-
type="email"错误提示固定,无法改文案;pattern必须配title属性才能显示友好提示,例如title="请输入正确邮箱格式" - Android Chrome 支持大多数正则语法,但 iOS Safari 不支持 lookbehind(
(?),写 pattern 时得绕开 -
type="number"会自动过滤非数字字符,但用户仍可粘贴字母,此时需额外用oninput清洗:this.value = this.value.replace(/[^0-9.]/g, '')
动态表格行内校验怎么避免监听器爆炸
每新增一行就给每个 <input> 绑一次 addEventListener,不仅容易漏绑,还会积累监听器引用,造成内存泄漏。更稳的做法是事件委托:把监听器挂在 <tbody> 上,靠 <code>event.target.matches('input[data-field]') 判断是否目标输入框。
实操要点:
- 每行
<tr> 加 <code>data-row-id,所有该行内<input>的name带下标,如amount-0、email-1 -
oninput只做输入净化(删非法字符),不改样式、不发请求;onblur才跑最终校验逻辑(比如金额范围、邮箱正则) - 校验结果存在 JS 对象里,键为
rowId,避免用全局变量或 DOM 属性存状态,否则异步插入后容易错乱 - 只调
setCustomValidity("错误")但没触发checkValidity(),界面毫无变化 - 在
input事件里频繁调setCustomValidity("")清空,结果用户还没输完就反复切换样式,体验卡顿 - 用
oninvalid事件覆盖提示,但它只在首次校验失败时触发,第二次失败就不进了,而且无法阻止默认弹窗
setCustomValidity 和 checkValidity 怎么配合用
setCustomValidity() 是手动控制校验状态的唯一入口,但它不会自动触发 UI 反馈;checkValidity() 才真正执行校验并触发 :invalid 伪类和错误提示。两者必须配合:先设状态,再调用检查。
典型误用场景:
真正可靠的节奏是:onblur 时校验 → 失败则 setCustomValidity("xxx") → 立即调 input.checkValidity() 触发反馈;成功则 setCustomValidity("") 并让 CSS 的 input:valid 规则接管样式。
最易被忽略的是:所有前端校验都只是体验层,required、pattern、setCustomValidity 全部可被禁用 JS 或 curl 绕过。后端必须用相同规则二次校验,并把错误字段精确映射回前端对应 name,否则用户填对了也提交失败。



















