HTML 表单
解释 form 如何把控件、校验与提交目标组织成可访问的数据收集单元,以及无 JS 渐进增强的基本闭环。
#concept
#growing
#frontend
#html
[!info] related notes
HTML 表单
这个概念为什么出现
登录、筛选库存、发起盘点——都是“收集字段并提交意图”。若只用一堆 input + div.onClick:
- 回车提交行为不一致
- 读屏难以把标签与控件关联
- JS 挂了就完全不可用
form 把字段、动作与提交控件收成一个语义单元。
[!abstract] 一句话理解 表单是浏览器内建的“数据收集与提交协议”;JS 应增强它,而不是先摧毁它。
最小可运行示例
场景:员工登录库存后台(无 JS 也要能提交)
<form action="/api/login" method="post">
<!-- 业务意图:提交工号与密码;教学点:label 通过 for/id 绑定可访问名 -->
<div>
<label for="employee-id">工号</label>
<input
id="employee-id"
name="employeeId"
autocomplete="username"
required
inputmode="text"
/>
</div>
<div>
<label for="password">密码</label>
<input
id="password"
name="password"
type="password"
autocomplete="current-password"
required
minlength="8"
/>
</div>
<!-- 教学点:显式 type=submit,避免 button 默认行为歧义 -->
<button type="submit">登录</button>
<button type="button">忘记密码</button>
</form>
建议验证:
1. 点击“工号”label 文字,应聚焦输入框
2. 空提交时浏览器原生拦截;无效时不会触发 submit 事件
3. 填写有效值后,以 method/action 指定方式提交;示例需配套 /api/login 服务端,单独打开 HTML 不会完成登录
结合场景关注点
name决定提交字段名,不是id。label绑定决定可访问名与点击热区。button的 type 在 form 内默认常为 submit,危险按钮要type=button。- JS 拦截提交时仍应保留键盘与校验路径。
核心模型
flowchart LR
U[用户填写] --> C[控件值]
C --> V[原生/自定义校验]
V -->|通过| S[提交 action/method 或 fetch]
V -->|失败| E[错误提示与焦点]
关键属性
| 属性 | 作用 |
|---|---|
action | 提交目标 URL |
method | HTTP 提交使用 GET/POST;dialog 用于关闭所属对话框,不发请求 |
enctype | 编码(文件上传 multipart) |
autocomplete | 浏览器自动填充提示 |
novalidate | 跳过提交时的原生交互式校验;布尔属性,出现即生效 |
设计动机
表单早于 SPA。规范把它做成声明式数据入口,让浏览器提供:键盘提交、自动填充、约束校验、历史与密码管理集成等能力。框架表单库应建立在这些能力之上。
边界与反直觉
novalidate="false"仍会跳过校验;要启用原生校验就移除该属性。- GET 表单会把字段放进 query,不适合密码;POST 本身不加密,登录仍需 HTTPS。\
- 多个 submit 按钮可用
name/value区分动作,提交数据中只包含实际提交按钮的这一项。 - 未命名、disabled、未选中的 checkbox/radio 通常不进入提交数据;readonly 文本控件仍会提交。\
form属性可让控件放在 form 元素外仍归属该表单。requestSubmit()按正常路径执行校验并触发 submit;直接form.submit()会绕过两者。- SPA 中
preventDefault后必须自己负责错误聚焦与成功反馈。
常见误区
[!warning] 常见误区:用 div 模拟 form 只剩样式 你会失去原生提交、自动填充与许多 a11y 默认行为。
工程实践
- 先写可无 JS 提交的结构,再加客户端增强;action 的服务端也必须支持相应编码与响应。\
- 错误信息与控件用
aria-describedby关联。 - 服务端永远再校验。
- 成功/失败状态见 提交状态处理。
本节总结
表单是产品数据入口的 HTML 合同:字段命名、标签绑定、提交方法与校验分层。
自测题
id与name分工?- 为什么删除
form只留 button onClick 是倒退?
参考答案
- id 用于文档内关联(label/for、脚本);name 用于提交数据集键名。
- 丢失回车提交、自动填充、原生校验与语义分组,可访问与稳健性下降。
延伸阅读
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| MDN: Web forms | 教程 | 表单体系 |
| HTML forms | 规范 | form 定义 |