Menu

HTML 表单:字段、action、method、fieldset 与验证

如何用 HTML 制作表单:form 元素、name 属性、action 和 method(GET 与 POST)、用 fieldset 和 legend 分组、用 required 和 pattern 做内置验证,以及用 JavaScript 处理提交。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

如何在 HTML 中制作表单

表单就是一个 <form> 元素,里面包含字段和一个提交按钮。每个字段都需要一个 name:它是发送值时使用的键。填写表单,然后点击 Send。预览不会把任何东西发送到任何地方;它会准确显示浏览器本来会发送的内容。

各个组成部分:

  • action 是数据要发送到的 URL,method 是发送方式(这里是 post)。
  • 每个字段都有 name。它的值就是读者输入的内容。
  • <label> 在屏幕上为每个字段命名,也为屏幕阅读器命名(参见 HTML label)。
  • required 和 type="email" 让浏览器在发送前检查字段。试试姓名留空发送,或者把邮箱填成 abc。
  • 提交按钮会发送表单。在文本字段中按 Enter 键也会。

action 和 method:数据发到哪里、怎么发

属性取值默认值
action任意 URL当前页面的 URL
methodget、post、dialogget
enctypeapplication/x-www-form-urlencoded、multipart/form-data、text/plainapplication/x-www-form-urlencoded

使用 method="get" 时,字段会变成 URL 的查询字符串:带 name="q" 的搜索表单会跳转到 /search?q=blue+shoes。这对搜索和筛选来说正合适,因为结果可以收藏为书签并分享。使用 method="post" 时,字段放在请求体中,不会出现在地址栏或历史记录里。凡是登录、创建、修改或删除东西的操作,以及涉及密码的表单,都要用 POST。

带文件上传(<input type="file">)的表单需要 method="post" 和 enctype="multipart/form-data",否则只会发送文件名。method="dialog" 用于 <dialog> 里的表单:提交时会关闭对话框,而不是发送请求。

会发送什么

只有带 name 的字段才会被发送,而且前提是它们没有被 disabled。点击 Submit,把字段和表单发送的内容对比一下:

表单发送了 city、zip、source 和 action。没有名称的字段、被禁用的字段和未勾选的复选框都被排除了。隐藏输入框会被发送,但永远不会显示;提交按钮会发送它自己的 name 和 value,因为提交时用的就是它。

用 fieldset 和 legend 给字段分组

<fieldset> 在相关字段周围画一个框,<legend> 是它的标题。焦点进入这一组时,屏幕阅读器会朗读 legend,正因如此,下面这样的一组单选按钮才能被理解:“Delivery, Standard, radio button”。

fieldset 上的 disabled 会一次性禁用其中的所有字段,它们都不会被发送。去掉它,礼品相关的字段就可以使用了。

内置验证:required、pattern 等

浏览器会在提交前检查这些属性,并在第一个未通过的字段上显示提示:

属性检查内容
required字段不为空(复选框已勾选)
type="email"、type="url"值看起来像邮箱地址或 URL
minlength、maxlength文本长度
min、max、step数字和日期的范围
pattern整个值匹配一个正则表达式

:invalid 和 :valid 根据字段状态设置样式。:user-invalid 通常更好:它只在读者修改过字段并离开、或者尝试提交之后才生效,所以空表单打开时不会满屏飘红。

pattern 有三点容易让人踩坑。它必须匹配整个值(不需要 ^ 或 $)。它只在字段不为空时才检查,所以要搭配 required 使用。另外浏览器的错误提示很笼统,所以要在字段旁边用可见的文字说明格式。Chrome 和 Firefox 会把 title 的文字加进提示里,但很容易被忽略。

要关闭这些检查,比如在测试服务器端验证时,给 <form> 加上 novalidate。单个提交按钮可以用 formnovalidate 跳过检查。

浏览器验证是为了方便读者。任何人都可以修改页面,或者绕过它直接发送请求,所以服务器必须重新检查每一个值。

用 setCustomValidity 自定义提示

当某条规则无法用属性表达时,比如“两次输入的密码必须一致”,就用 JavaScript 设置提示。自定义提示不为空的字段是无效的;设为空字符串就会让它重新变为有效:

重复输入的字段没有 name,所以密码只会发送一份。

用 JavaScript 处理提交

要在不离开页面的情况下发送表单,就监听 submit,调用 preventDefault(),再用 FormData 读取字段。监听 submit 而不是按钮的 click,可以捕获所有提交方式,包括按 Enter 键,而且只会在内置验证通过之后才运行:

Object.fromEntries(new FormData(form)) 把字段转换成一个普通对象。对于可能有多个值的字段(同名的多个复选框、多选的 select),请改用 formData.getAll('name'),因为对象只保留最后一个值。

常见错误

  • 字段没有 name。 它们会被悄无声息地排除在提交的数据之外。
  • 用占位符代替标签。 读者一开始输入,提示就消失了。请用 <label>。
  • 没有 type 的 <button> 被用来做提交以外的事情。在表单里,它默认就是提交按钮。
  • 表单里嵌套表单。 嵌套表单是无效的;浏览器会忽略内层的 <form> 标签。
  • 监听提交按钮的 click,而不是表单的 submit。这样会漏掉用 Enter 键提交的情况。
  • 在服务器端信任浏览器验证。 在服务器上要再验证一次。
  • 用 GET 发送密码。 密码会出现在 URL、历史记录和服务器日志里。

常见问题

HTML 中怎么创建表单?

用 <form action="/signup" method="post"> 包住各个字段,给每个字段一个 name 和一个 <label>,最后放一个 <button type="submit">。表单提交时,浏览器会把每一对 name=value 发送到 action 指定的 URL。

表单中的 GET 和 POST 有什么区别?

method="get"(默认值)把字段放进 URL,例如 /search?q=shoes,适合需要能收藏为书签的搜索和筛选。method="post" 把字段放在请求体中发送,登录、注册以及任何会修改数据的操作都应该用它。

为什么我的表单字段没有被提交?

它没有 name 属性,或者它是 disabled 的。只有带名称且未禁用的字段才会被发送。未勾选的复选框或单选按钮也会被完全忽略。

fieldset 和 legend 有什么用?

<fieldset> 把相关字段分成一组,<legend> 是这一组的标题。焦点进入这一组时,屏幕阅读器会朗读 legend,这正是一组单选按钮能被理解的原因;给 fieldset 加上 disabled 会禁用其中的所有字段。

不用 JavaScript 怎么验证 HTML 表单?

使用属性:required、type="email"、minlength、maxlength、min、max 和 pattern。浏览器会阻止提交,并在第一个无效字段上显示提示。服务器端也一定要再验证一次,因为这些检查在读者的浏览器中运行,可以被绕过。

怎样阻止表单提交后刷新页面?

监听表单的 submit 事件并调用 event.preventDefault(),然后自己用 fetch 发送数据:form.addEventListener('submit', (e) => { e.preventDefault(); fetch(form.action, { method: 'POST', body: new FormData(form) }); })。

Coddy 编程语言插图

和 Coddy 一起学编程

开始