C02 表单校验进阶

2026-10-31 14:500 阅读约 13 分钟HTML

摘要:浏览器原生校验能拦住空值与格式,但提示文案不可改、错误分散在字段旁、朗读软件未必播报。要做出可用又可维护的校验,需要四层配合:约束属性负责基础拦截,样式负责视觉反馈,少量脚本负责自定义规则与汇总,服务端负责最终判定。本文给出这套组合的完整代码与三条判定标准。
关键词:约束校验,自定义校验,错误提示,无障碍表单,服务端校验

所属:frontend/html / C-高级 | 上一篇:C01-无障碍与ARIA | 下一篇:C03-资源提示与性能

1 引言

表单校验的失败通常不在「没写校验」,而在分层混乱:把业务规则塞进 pattern,或者只用脚本校验却在脚本失效时全部放行。

本文给出四层校验的分工与一份可运行的实现。范围见表 1-1。

项 本文覆盖 本文不覆盖
约束 required、type、min/max、minlength、pattern、step 正则表达式系统讲解
反馈 错误文案位置、aria-invalid、aria-live 汇总 设计系统与组件库
脚本 novalidate、setCustomValidity、reportValidity 框架表单状态管理
服务端 校验必要性与错误回传方式 接口实现与防重放

2 预备知识

项 要求 核对方式
环境 A02 的本地服务器 能访问 localhost
前置 A07 表单控件与 label 关联已掌握
前置 C01 能使用 aria-live 与名称属性
文件 html-practice/validate.html 编码 UTF-8

3 原理与实现

3.1 四层校验的分工

四层校验各自负责不同阶段,越往后越不可省略,如图 3-1 所示。

flowchart TD
    A["用户输入"] --> B["约束属性<br/>required / type / pattern"]
    B -->|"不通过"| E["浏览器原生提示"]
    B -->|"通过"| C["脚本增强<br/>自定义规则与汇总"]
    C -->|"不通过"| F["字段描边 + 汇总区文本"]
    C -->|"通过"| D["服务端校验"]
    D -->|"不通过"| G["回传错误并回填表单"]
    D -->|"通过"| H["进入业务流程"]

图 3-1 校验的四层分工

图上可见:前两层都可被绕过,服务端校验是唯一不可跳过的判定点;脚本层的价值在于提示质量,不在于安全。

3.2 脚本增强与可访问提示

<!-- 运行环境:Chrome 130+;body 内内容 -->
<form id="signup" novalidate>
  <p>
    <label for="email">邮箱</label>
    <input
      id="email"
      name="email"
      type="email"
      required
      autocomplete="email"
      aria-describedby="email-error"
      inputmode="email"
    />
    <span id="email-error" role="alert"></span>
  </p>

  <p>
    <label for="handle">用户名</label>
    <input
      id="handle"
      name="handle"
      type="text"
      required
      minlength="3"
      maxlength="16"
      pattern="[a-z0-9_-]+"
      aria-describedby="handle-hint handle-error"
    />
    <span id="handle-hint">3 ~ 16 位小写字母、数字、下划线或连字符。</span>
    <span id="handle-error" role="alert"></span>
  </p>

  <p aria-live="polite" id="summary"></p>

  <button type="submit">提交</button>
</form>

<script>
  const form = document.getElementById('signup');
  const handle = document.getElementById('handle');
  const handleError = document.getElementById('handle-error');
  const summary = document.getElementById('summary');
  const reserved = ['admin', 'root', 'system'];

  handle.addEventListener('input', () => {
    if (reserved.includes(handle.value)) {
      handle.setCustomValidity('该用户名已被保留,请更换。');
      handleError.textContent = '该用户名已被保留,请更换。';
      handle.setAttribute('aria-invalid', 'true');
    } else {
      handle.setCustomValidity('');
      handleError.textContent = '';
      handle.removeAttribute('aria-invalid');
    }
  });

  form.addEventListener('submit', (event) => {
    event.preventDefault();
    if (!form.checkValidity()) {
      const firstInvalid = form.querySelector(':invalid');
      summary.textContent = `共 ${form.querySelectorAll(':invalid').length} 项需要修正。`;
      firstInvalid.focus();
      return;
    }
    summary.textContent = '校验通过,可以提交。';
  });
</script>

约束属性与校验时机见表 3-1。

属性 / 事件 作用 注意点
required 必填 只拦空值,不拦空格
type="email" 邮箱格式 允许 a@b 这类宽格式
minlength 最小长度 与 maxlength 成对使用
pattern 正则约束 默认整串匹配,不加 ^$ 也可
setCustomValidity 注入自定义错误信息 规则解除时必须清空为空串
novalidate 关闭浏览器默认提示,交由脚本处理 关闭后仍需保留约束属性
checkValidity() 主动触发校验,返回布尔值 不显示浏览器提示
reportValidity() 触发校验并显示浏览器提示 用于需要原生样式的场景

错误提示的放置方式对比见表 3-2。

方式 可读性 实现成本 适用场景
浏览器原生气泡 一致但不可定制 零 内部工具、原型
字段下方内联文本 明确,需 aria-describedby 低 大多数表单
顶部汇总区 便于整体判断错误数量 中 长表单、批量录入
仅改变边框颜色 色觉差异人群不可用 低 不应单独使用

4 验证与讨论

  1. 留空提交,确认焦点跳到首个错误字段,汇总区显示需要修正的项数。
  2. 用户名输入 admin,确认出现自定义提示且提交被拦下;改为 liming 后提示消失。
  3. 使用朗读软件或无障碍面板,确认错误文本与字段的关联存在。
  4. 删除脚本(或禁用 JavaScript),提交相同数据,确认约束属性仍然生效。
检查项 预期结果 说明
焦点定位 首个错误字段获得焦点 4 节步骤 1
自定义规则 admin 被拦下 setCustomValidity
错误关联 面板显示字段与描述的关联 aria-describedby
汇总播报 播报错误项数 aria-live="polite"
无脚本可用 仍能拦住空值与格式错误 约束属性仍在

讨论与局限。 setCustomValidity 的错误会一直保留,直到显式清空为空串,忘记清空会导致整个表单无法提交。另 pattern 在不同输入法与移动键盘下行为不完全一致,手机号、证件号这类规则最终仍以服务端为准。

5 常见问题

现象 原因 处理
修改后仍提示自定义错误 未在规则解除时清空 调用 setCustomValidity('')
提交后没有任何提示 表单加了 novalidate 但没写脚本 补脚本,或去掉 novalidate
错误文本不播报 提示容器无 role="alert" 或 aria-live 补属性
空格通过必填校验 required 不校验空白字符 提交前 trim() 后再判断
移动端键盘类型不对 未设置 inputmode / type 邮箱用 type="email",数字用 inputmode="numeric"

6 结论

序号 结论 依据
1 四层校验各负其责,服务端不可省略 图 3-1
2 自定义错误必须能被清空 表 3-1
3 错误提示需与字段建立描述关联 表 3-2
4 禁用脚本后的表现是校验可靠性的下限 4 节步骤 4

参考文献

[1] MDN Web Docs · 客户端表单校验,https://developer.mozilla.org/zh-CN/docs/Learn/Forms/Form_validation(访问于 2026-10-29)
[2] HTML Living Standard · Constraint validation,WHATWG,https://html.spec.whatwg.org/multipage/form-control-infrastructure.html(访问于 2026-10-29)

返回文章列表

评论 0

0/2000

还没有评论,快来抢沙发吧~