学习前提

理解标签与属性,能够创建链接。先用示例数据练习。

本课完成后你能做什么

解释 label、id、name 的不同作用,区分输入校验与可信数据,并观察表单提交的数据格式。

先理解机制

id 用来在文档中定位元素,label 的 for 引用它;name 决定提交数据里的键名。只给 input 设置 id 并不会自动得到同名提交字段。表单不是几个输入框的集合,而是在描述一次有目标的输入任务。相关单选按钮可以放入 fieldset,用 legend 表示整组问题,避免每一项只能依赖视觉位置解释。

浏览器的 required 和 type=email 帮助用户尽早发现问题,但只是在客户端提供反馈,不是服务端的信任边界。用户可以绕过客户端限制。GET 通常把成功控件的数据放进 URL 查询串;POST 通常放进请求体,但 POST 本身不提供加密。真实服务端仍要按业务规则校验并使用合适的传输保护。

可运行示例

<form>
  <label for="email">Email</label>
  <input id="email" name="email" type="email" required>
  <button type="submit">Check</button>
</form>

推演与验证

先提交空输入,浏览器应阻止正常提交;输入不含 @ 的内容再提交,检查格式提示。使用 [email protected] 后查看地址栏,默认 GET 会产生查询参数。将 input 的 name 删除再提交,观察该字段不再进入数据。此实验没有接收数据的后端,不能把页面跳转当成注册成功。

常见错误与边界

placeholder 不能替代始终可见的 label。button 在表单中默认可能提交,因此辅助按钮要显式使用 type="button"。disabled 控件通常不会被提交;readonly 控件仍可提交。不要让错误只表现为红色边框,要提供可理解的文字。

动手练习

增加昵称字段,必填且最多30字符;增加“清空说明”按钮但不让它提交。解释为什么只加 maxlength 仍不足以保证服务器收到的数据合规。

参考解法与理由

昵称同时需要 id、name 和匹配的 label。辅助按钮用 type="button"。maxlength 是界面约束,服务端还需要检查长度、类型和业务允许的字符;验证失败时返回与字段对应的错误,而不是把所有错误归为网络问题。

<label for="nickname">Nickname</label>
<input id="nickname" name="nickname" required maxlength="30">
<button type="button">Show instructions</button>

深入实验:看得见的输入不一定会提交

表单提交的是有名称且符合提交规则的控件数据,不是页面截图。只读、禁用、未勾选和没有name的字段含义不同。下面只构造FormData,不发送网络请求,便于先理解数据契约。

在现代浏览器Console中独立运行这个实验;它不替换上方主示例。

const form = new DOMParser().parseFromString(`<form><input name="course" value="html" readonly>
<input name="level" value="beginner" disabled>
<input value="visible-but-unnamed">
<input type="checkbox" name="news" value="yes">
<input type="checkbox" name="topic" value="html" checked>
<input type="checkbox" name="topic" value="css" checked></form>`, 'text/html').forms[0];
const data = new FormData(form);
console.log(JSON.stringify([...data]));
console.log(JSON.stringify(data.getAll('topic')));
console.assert(!data.has('level') && !data.has('news'));
console.assert(data.getAll('topic').length === 2);

预期观察

条目依次是course=html、topic=html、topic=css;getAll返回["html","css"]。readonly字段被包含,disabled字段不包含。

原因、取舍与适用边界

Object.fromEntries会把同名字段折叠成一个属性,可能丢失复选框组的前几项,因此数组字段应使用getAll并逐项校验。readonly只约束正常界面操作,不能证明值可信;用户可以修改DOM或直接构造请求。FormData本身也不会自动执行完整的约束校验,服务端仍要验证必填、类型、范围和权限。

进阶练习

加入一个默认未勾选的agree字段,要求提交前明确同意。如何区分缺失与值为no?

解法与推理

给checkbox配置明确的value=yes和required,用requestSubmit触发正常提交校验;读取端检查是否存在且值恰好为yes。缺失不是字符串no。若后端接口要求布尔值,在提交适配层显式转换,不要用Boolean("false"),它会得到true。

进一步阅读