blur事件是失焦验证的唯一可靠选择,因其语义准确、兼容性好、触发稳定且仅在用户主动移开焦点时发生一次;change漏验未修改内容的情况,focusout易因冒泡被拦截或重复执行。

blur事件是失焦验证的唯一可靠选择
别用change或focusout做失焦校验——change只在值真正改变后才触发,用户没改内容就点别处,校验直接漏掉;focusout会冒泡,容易被父容器拦截或重复执行。blur语义准确、兼容性好、触发稳定,且只在用户主动移开焦点时发生一次。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 对每个
<input>单独绑定addEventListener('blur', handler),避免事件委托(需要读取当前元素的value、dataset等) - 若需支持回车提交同时触发校验,额外监听
keydown并判断Enter键 - 校验逻辑里必须显式调用
setCustomValidity('')重置状态,否则用户改对了也一直报错
focus时清除提示要分清原生和自定义
浏览器原生提示(如title属性)和前端自定义提示(如<span class="error-msg"></span>)清除方式完全不同,混用会导致部分提示残留或无障碍失效。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 原生
title提示:保存初始值,在focus时设为空字符串input.title = '',blur时恢复input.title = originalTitle - 自定义提示元素:用
data-for关联输入框ID,focus时切换hidden类或设style.display = 'none',推荐用class切换便于CSS过渡 - 校验样式类(如
invalid)和aria-invalid属性也要在focus时同步清除,否则视觉与语义不一致
setCustomValidity不是“设了就生效”
setCustomValidity只修改元素的验证状态,不会自动弹气泡、不触发:invalid伪类更新、也不阻止表单提交——它必须配合验证触发时机才能起作用。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 设错误信息:
input.setCustomValidity('邮箱格式不对');清空错误:input.setCustomValidity('')(注意是空字符串,不是null或undefined) - 想立刻看到原生气泡,得手动调
input.reportValidity();但生产环境更推荐用CSS类+旁白元素做反馈,别依赖气泡 - 仅调
setCustomValidity后,checkValidity()返回值仍会更新,但:invalid类需再触发一次验证(如blur或submit)才会刷新
novalidate不是关掉验证,而是移交控制权
novalidate加在<form>上,只是禁用浏览器默认的提交拦截和气泡提示,所有验证API(checkValidity、validationMessage、reportValidity)依然可用。加在<button>或<input>上完全无效。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 加
novalidate后,submit事件里必须event.preventDefault(),否则页面刷新,JS状态全丢 - 仍可调
form.checkValidity()判断整体状态,再手动聚焦第一个错误项:firstInvalidInput.focus() -
form.reportValidity()仍会触发原生提示,一般只用于调试,正式流程应由JS统一控制反馈样式和文案
最易被忽略的是:blur验证和focus清理必须成对设计,且各自独立维护状态。比如一个字段既有required又有pattern,又叠加了setCustomValidity,三者验证逻辑不同步,就会出现“提示消失了但边框还是红的”这类问题。



















