<form> 元素:收编了哪些控件,提交去哪里
<form> 是表单的容器,但它真正的职责是两件事:收编一批控件(form ownership,决定提交时谁的值会被收集)与描述提交去向(action / method / enctype /
target)。规范里有两个常被误解的点:控件归属哪个表单不取决于视觉位置,而取决于 DOM 祖先或 form 属性——一个写了 form="someId" 的控件可以待在 <form> 之外、却仍被它提交;以及 form.action /
form.method 这些 IDL 属性读出来的值经过规范化,未必等于你写的 attribute。本页用一个 live form inspector 把这些当场点出来。
1 · form ownership:谁被这张表单收编
下面紫框是 <form id="ownerForm">,虚线框是它之外的 DOM。虚线框里的复选框写了 form="ownerForm"——改它、改框内任意控件,右侧 form.elements 列表都会把它一并算进来。form.elements 收录的是这张表单的全部
listed elements,无论它们在 DOM 里待在哪。
listed elements,以及 form.elements 的一个历史例外。 form.elements 收录
以及 form-associated custom element——统称 listed elements。唯一的例外:<input type="image"> 出于历史原因被排除在 form.elements 之外(但提交时它仍是 successful control)。注意上面那个没写 name 的输入框:它在
elements 里(可被脚本访问),但提交时不进 entry list,详见 提交算法与三种编码。
2 · action / method / target:提交去向也经过规范化
改下面的 action 与 method,看 IDL 属性读出来的值。两个反直觉点:form.action 把相对路径解析成了当前页的绝对 URL(attribute 留空时直接返回本页 URL);form.method 只认 get / post /
dialog 三个值,写别的会被规范化回 get。
<form> 属性 |
作用 |
|---|---|
action |
提交的目标 URL。省略 = 提交到当前页 URL。 |
method |
get(默认,值进 query string)/ post(值进请求体)/ dialog(在 <dialog> 内关闭对话框,不导航)。 |
enctype |
仅对 post 生效的请求体编码:urlencoded / multipart / text/plain。详见 提交算法。 |
target |
结果在哪打开:_self(默认)/ _blank / _parent / _top 或具名 frame。 |
novalidate |
提交前跳过约束校验。单个 submit 按钮可用 formnovalidate 局部覆盖。详见 约束校验。 |
rel |
导航关系,如 noopener / noreferrer(配合 target=_blank)。 |
autocomplete |
on / off——整张表单的自动填充默认开关。详见 autocomplete。 |
3 · 同一份代码里的三件事
<!-- 1. 提交去向:GET /search?q=…&category=… -->
<form id="ownerForm" action="/search" method="get">
<input name="q" />
<select name="category">…</select>
<input value="无 name —— 不会被提交" />
</form>
<!-- 2. 控件在 form 之外,靠 form 属性关联进 ownerForm -->
<label>
<input type="checkbox" name="newsletter" form="ownerForm" />
订阅邮件
</label>
<!-- 3. 脚本里读到的是规范化后的值 -->
ownerForm.method // "get"(写 method="PUT" 也读成 "get")
ownerForm.action // "https://site/search"(绝对 URL)
[...ownerForm.elements] // 含上面那个 form 外的 checkbox
ownerForm.elements.q.value // 具名访问,等价 ownerForm.q.value
<form> 不能嵌套。 HTML 解析器遇到嵌套的 <form> 会直接忽略内层开标签,内层那批控件最终归属外层表单。需要把字段拆给不同 action 时,正确做法是并排两个 form + 用 form 属性把控件关联过去,而不是物理嵌套。
method="dialog" 是一条特殊路径。 当 <form method="dialog"> 位于 <dialog> 内部,提交时不发任何网络请求、不导航,而是关闭对话框,并把触发提交的按钮 value 写进
dialog.returnValue。这把「表单提交」复用成了「对话框确认」的语义,详见 Dialog / Popover 系列。
具名访问:form.elements.q 与 form.q。 表单控件可通过 name 或 id 直接从 form.elements(HTMLFormControlsCollection)或 form 本身按名取到——同名多个(如一组 radio)则返回
RadioNodeList。这是无框架时代读写表单值的原生方式,至今仍可用。