原生表单校验需明确触发时机与状态流转,仅submit事件触发批量校验;required仅判空、pattern对number等类型无效且自动加^$;实时反馈须手动调checkValidity()和reportValidity();validity对象的12个属性才是校验依据。

原生表单校验不是“加了属性就自动生效”,它有一套明确的触发时机、状态流转和浏览器干预逻辑。没搞清这套机制,required 会像没写一样,pattern 会始终不报错,setCustomValidity 会卡死提交。
submit 事件是原生校验的唯一默认触发点
浏览器只在 form 元素收到 submit 事件时,才批量检查所有子控件的 validity 状态。这包括:button type="submit"、input type="submit",或用户按回车(前提是焦点在可提交控件上)。用 form.submit() 调用 JS 方法、或 button type="button" 绑定 click 后手动提交,都会跳过全部原生校验。
-
required只判断是否为空(valueMissing),不校验内容格式;空格字符串对type="text"算“已填”,但对type="number"会被 trim 后判空 -
type="email"的校验极宽松:只要含一个@和至少一个.(如a@b.c或user@localhost)就通过,真要校验邮箱必须配pattern - 提交前若某字段
validity.valid === false,浏览器会阻止提交,并在第一个失败字段聚焦、弹出气泡提示(Chrome 行为;Firefox 不自动滚动)
pattern 属性只对部分 type 生效且有隐式边界
pattern 实际只作用于 type="text"、"search"、"tel"、"url"、"email"、"password" 这几类。它对 type="number"、"date"、"checkbox" 完全无效——这些类型有自己的解析逻辑,pattern 被忽略。
- 浏览器会自动给你的正则加上
^和$,所以写pattern="[a-z]{3,}"即可,别写pattern="^[a-z]{3,}$",否则 Chrome 会报Invalid regular expression - 中文需显式包含 Unicode 范围,
w不匹配汉字;正确写法如pattern="[u4e00-u9fa5a-zA-Z0-9]{2,10}" - 想排除开头数字?用负向先行断言:
pattern="(?!\d)[a-zA-Z0-9]{6,12}"(注意 JS 字符串里双反斜杠)
实时反馈必须手动调用 checkValidity() 和 reportValidity()
原生校验默认不监听 input 或 blur,要实现输入中提示,得自己接管流程:
立即学习“前端免费学习笔记(深入)”;
- 监听
input事件,在回调里调element.checkValidity()判断当前值是否合法 - 用
element.setCustomValidity("")清空旧错误(否则即使输对了也一直报错),校验失败时再设具体错误字符串 - 调
element.reportValidity()才能强制弹出浏览器默认气泡——但它不保证滚动到该字段,也不统一跨浏览器行为 - 更稳妥的做法是:自己读取
element.validationMessage,渲染到旁边<span class="error"></span>里,用 CSS 控制显隐
invalid 事件和 validity 对象才是调试关键
不要靠 value === "" 判断必填,而应查 element.validity.valueMissing;不要靠正则 test 结果,而应看 element.validity.patternMismatch。整个 validity 对象暴露了 12 个布尔属性,每个对应一类失败原因:
-
valueMissing:required 未填 -
typeMismatch:如type="email"但没@ -
patternMismatch:正则不匹配 -
tooShort/tooLong:长度超限 -
rangeUnderflow/rangeOverflow:数值/日期超出 min/max
这些属性才是你写自定义提示、做条件分支、甚至打日志定位问题的可靠依据。浏览器的气泡提示文本,就是由这些状态组合生成的 validationMessage。



















