← HTML 表单:从控件到提交与校验 / <form> 元素:收编了哪些控件,提交去哪里 待审核 5 / 24
form · action / method · ownership

<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 收录 buttonfieldsetinputobjectoutputselecttextareabutton \cdot fieldset \cdot input \cdot object \cdot output \cdot select \cdot textarea 以及 form-associated custom element——统称 listed elements。唯一的例外:<input type="image"> 出于历史原因被排除在 form.elements 之外(但提交时它仍是 successful control)。注意上面那个没写 name 的输入框:它在 elements 里(可被脚本访问),但提交时不进 entry list,详见 提交算法与三种编码

2 · action / method / target:提交去向也经过规范化

改下面的 actionmethod,看 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.qform.q 表单控件可通过 nameid 直接从 form.elementsHTMLFormControlsCollection)或 form 本身按名取到——同名多个(如一组 radio)则返回 RadioNodeList。这是无框架时代读写表单值的原生方式,至今仍可用。