优雅的表单验证需手动控制提示位置、时机与可访问性:每个input后紧跟role="alert"的error元素,显式绑定data-error-target;preventdefault后须遍历字段调checkvalidity、设aria-invalid和aria-describedby、清空旧状态并聚焦错误项;隐藏提示用visibility:hidden而非display:none,动态修改required属性须同步更新dom。

直接用浏览器原生验证气泡不是优雅,是妥协。真要优雅,得自己控制提示位置、时机、可访问性和视觉稳定性。
错误提示必须紧挨 input 插入,不能塞进 label 或父容器末尾
插错位置会导致屏幕阅读器找不到错误,键盘用户 tab 过去也看不见提示。label 里塞文案会破坏语义,父容器末尾放又脱离视觉动线。
- 每个
input后面紧跟一个<div class="error" role="alert" aria-live="polite"></div> - 用
data-error-target="#error-email"显式绑定,别靠 class 名全局查 ——document.querySelector(".error")永远只改第一个 - 禁用
title和placeholder承载错误:前者移动端不可触达,后者 focus 后就消失,都不满足 WCAG 要求
preventDefault() 后不手动接管,就等于没校验
一旦在 submit 事件里调了 event.preventDefault(),浏览器原生的气泡、红框、:invalid 样式更新全失效。这不是 bug,是你主动声明“我来负责”。
- 必须遍历所有字段,对每个
input单独执行:el.checkValidity()→ 判断失败 → 清空/写入对应data-error-target元素 → 设aria-invalid="true"→el.setAttribute("aria-describedby", errorId) - 校验失败后记得
el.focus(),否则用户卡在提交按钮,根本不知道哪错了 - 漏掉
el.setCustomValidity("")清空旧状态?输对了也一直报错
隐藏错误提示别用 display: none,用 visibility: hidden
display: none 会导致布局重排,输入框上下元素“抽搐”;visibility: hidden 保留占位,视觉稳定,也兼容屏幕阅读器对 role="alert" 的播报逻辑。
- 用 CSS 控制
.error { display: block; margin-top: 0.25rem; visibility: hidden; },JS 里只切visibility: visible - 用
innerHTML = ""清空提示后,忘了重置visibility?后续报错就不显示 - 多个字段共用同一段 JS 验证逻辑时,错误显隐必须按字段单独控制,不能“一起弹出/一起消失”
最常被忽略的是:动态开关 required 时,只改 JS 判断不行,得同步设 el.required = true/false,否则 checkValidity() 结果不准,辅助技术也感知不到变化。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











