目录
- [1. 用户交互](#1. 用户交互)
- [2. 按钮](#2. 按钮)
- [3. 表单的结构](#3. 表单的结构)
-
- [3.1 \<form\>元素](#3.1 <form>元素)
-
- [3.1.1 检查提交的数据](#3.1.1 检查提交的数据)
- [3.1.2 结构化表单](#3.1.2 结构化表单)
- [3.2 \<input\>元素](#3.2 <input>元素)
-
- [3.2.1 required和value属性的实际效果](#3.2.1 required和value属性的实际效果)
- [3.2.2 特定类型的文本输入框](#3.2.2 特定类型的文本输入框)
- [3.3 \<label\>元素](#3.3 <label>元素)
-
- [3.3.1 显式与隐式表单标签](#3.3.1 显式与隐式表单标签)
- [3.4 \<button\>元素](#3.4 <button>元素)
- [4. 关于无障碍的小提示](#4. 关于无障碍的小提示)
- [5. 其他控件类型](#5. 其他控件类型)
-
- [5.1 单选按钮](#5.1 单选按钮)
-
- [5.1.1 禁用表单控件](#5.1.1 禁用表单控件)
- [5.2 复选框](#5.2 复选框)
- [5.3 下拉菜单](#5.3 下拉菜单)
- [3.4 多行文本输入框](#3.4 多行文本输入框)
- [6. 表单验证](#6. 表单验证)
- 参考
1. 用户交互
用户和网页交互的几种方式:
链接可用于导航到同一页面或不同页面的不同内容部分。
<video>和<audio>元素通常含有播放/暂停、快进、回退等功能,允许用户根据需要来消费媒体内容。
然而,这些功能通常更偏向于单向交互,让用户被动地消费内容。虽然这没问题,但Web是一种双向体验。网站用户会根据自己的喜好调整内容和服务的使用方式。
要实现这种双向交互体验,你需要使用按钮和表单。
按钮通常是通过HTML的<button>元素创建的(有时也使用<input>元素并将其type属性设置为button或submit值)。这些按钮用途广泛------你可以将它们与任意功能关联,实现什么功能只取决于你的想象力和编码能力。
表单是通过<form>、<label>、<input>和<select>等元素创建的。与简单的按钮相比,表单元素可以创建更复杂的控件------例如包含多个选项的下拉菜单,允许用户在不同的用户界面主题之间进行选择。
更重要的是,它们还可以用于创建表单,供用户在需要向网站服务器提交信息时填写。
2. 按钮
最简单的按钮如下:
html
<button>点击这里</button>

出现在<button></button>标签的文字会显示在按钮内部,并且浏览器会为其应用一些基础样式,使它默认看起来和表现得像一个按钮。给它添加一些Javascript代码:
html
<button>点击这里</button>
<script>
const btn = document.querySelector("button");
btn.addEventListener("click", () => {
btn.textContent = "你点击了这个按钮!! ❤️";
setTimeout(() => {
btn.textContent = "点击这里";
}, 1000);
});
</script>

3. 表单的结构
一个基础的表单包含以下三个部分:
一个<form>元素,用于包裹表单的所有提交内容。所有包含在<form></form>标签内的表单控件都属于同一个表单,它们的数据会在表单提交时一起发送。
一对或多对<label>元素与表单控件元素(通常是<input>元素,但也有其他类型,例如<select>):
表单控件元素允许用户选择或输入一些数据,这些数据将在表单提交时发送到服务器。
<label>元素为表单控件提供一个标识标签,用于描述应在控件中输入的数据内容。
一个<button>元素,用于提交表单。
html
<form action="./submit_page" method="get">
<h2>订阅我们的新闻简报</h2>
<p>
<label for="name">姓名(必填):</label>
<input type="text" name="name" id="name" required />
</p>
<p>
<label for="email">邮箱(必填):</label>
<input type="email" name="email" id="email" required />
</p>
<p>
<button>订阅新闻简报!</button>
</p>
</form>

如果填写了数据点击按钮,会看到一个404错误页面。
3.1 <form>元素
<form>元素作为表单的外层容器,用于将所有的表单控件组织到一起。当点击<button>按钮时,所有在表单控件中填写的数据都会被提交到服务器。<form>元素可以包含多个属性,最重要的两个属性是:
action:包含一个路径,用于指定提交的表单数据将发送到哪个页面进行处理。稍后,当你提交表单时,你会在URL中看到/submit_page。你还会受到一个404错误响应,因为处理数据的页面实际上并不存在,但目前这样做是没问题的。
method:指定将表单数据发送到服务器时使用的数据传输方法。现在你不必太过担忧这个属性;当值为get时,数据会作为参数附加在URL的末尾进行发送。
3.1.1 检查提交的数据
在上面示例中的表单中填入姓名Bob,电子邮件地址bob@bob.com,点击提交按钮。action和method属性会使表单数据以下列URL形式提交:
/some/url/submit_page?name=Bob&email=bob%40bob.com
3.1.2 结构化表单
可以在<form>元素中包含任意的HTML元素,用于组织表单控件本身,并为CSS样式提供可定位的容器,以便进行样式设置等操作。
在示例中,使用了一个<h2>来描述该表单的用途。还将每一对输入框/标签和提交按钮分别放在一个单独的<p>元素中,这样每一组控件就会独占一行上。这些元素默认是行内的,这意味着如果不这么做,所有的控件将会处于同一行。
这是表单结构化的常见形式。一些人使用<p>元素来分割表单控件,一些人使用<div>、<section>甚至是<li>元素。只要使用的元素在语义上合理,这些其实并没有太大区别。但使用块级引用元素、侧边栏元素或者是联系人地址元素来表示就不太合适。
还有一个专门用来对表单控件进行分组的元素:<fieldset>。当表单较复杂,或需要把多个复选框、单选按钮归为一组时,它就非常有用。
3.2 <input>元素
<input>元素表示用户在表单中输入的各种数据项。
html
<input type="text" name="name" id="name" required />
type:指定要创建的表单控件类型。表单控件类型有很多,从各种简单的文本字段,到单选按钮、复选框等。当值为text时,会渲染一个可接受任何文本的基本文本框。
name:为该数据项指定一个名称。当表单提交时,数据会以名值对的形式发送。一般来说,name属性的值就是这个数据项的名称,而用户在文本框输入的数据就是这个数据项的值。
id:指定一个用于标识该元素的ID。在这里,它用于将该表单控件与对应的<label>标签关联起来。
required:指定该表单控件在提交表单前必须填写。这应仅用于必填字段,而不应设置在可选字段上。
有些输入类型的值并不是用户直接在字段输入的。<input type="color">会显示一个取色器,你可以从中选择颜色;<input type="radio">会显示一个单选按钮,可以被选中也可以不被选中。
对于单选按钮,一般需要在value属性中指定一个具体的值,表示当该按钮被选中时,提交到服务器的实际内容。也可以在text和color等输入类型上也设置value属性,其效果是:表单控件在初次渲染完成时就预先填充这个值。
3.2.1 required和value属性的实际效果
在之前示例没有填写内容的情况下提交表单。你会看到一条错误提示。

在姓名中填写有效的名字,在电子邮件地址中填入123。点击提交会给出关于电子邮件地址的错误提示。

尝试在第一个<input>中加入value属性,值为Bob。你会看到第一个输入框中默认填入了Bob。

3.2.2 特定类型的文本输入框
示例中第二个输入字段特别要求输入一个邮箱地址,并会对填写的内容进行邮件格式的验证。第二个<input>元素的type为email。还有许多专门用于处理特定类型数据的文本字段输入类型:<input type="number">、<input type="password">、<input type="tel">等。
3.3 <label>元素
<label>元素为表单控件提供了标识性标签,用于描述应该在控件中输入的数据。你可以在<label>元素中放置任意文本内容,但这些内容应该准确描述关联表单控件所期望的数据类型。标签与控件之间的关联方式是:给表单控件设置一个id属性,然后给<label>设置for属性,其值与该控件的id相同。
html
<label for="name">姓名(必填):</label>
<input type="text" name="name" id="name" required />
<label>元素的重要性体现在多个方面,尤其包括以下几点:
当视力障碍用户使用屏幕阅读器浏览和操作网页内容时,屏幕阅读器在遇到每个控件时,会朗读与之关联的标签文本。这能让用户更容易理解每个控件需要输入什么内容。
它们允许用户不仅可以点击控件本身,还可以点击标签文本来聚焦表单控件。这对移动设备用户尤其有用,因为在触摸屏上用手指精确选择表单控件可能比较困难。在这种情况下,扩大可点击区域会非常有帮助。
3.3.1 显式与隐式表单标签
示例中的标签样式被称为显式表单标签------控件与标签之间的关联是通过id和for属性显式建立的。你也可以通过将控件嵌套在标签内的方式实现隐式表单标签。
html
<label>
姓名(必填):
<input type="text" name="name" required />
</label>
通过嵌套方式,控件与标签之间的关联是隐式建立的,因此你不再需要id和for属性。但更建议使用显式标签。
3.4 <button>元素
当一个<button>元素被放在form元素中时,它的默认行为是提交表单,只要没有无效数据阻止客户端表单验证。
通过<button>元素的type属性可以指定按钮的其他行为:
<button type="submit">明确声明该按钮是提交按钮。一般来说不需要显式声明,除非你的<form>中包含了多个按钮,并且你想明确表示哪个按钮是用于提交表单的。
<button type="reset">创建一个重置按钮------这会立即清空表单中输入的所有内容,将表单恢复到初始状态。不建议使用重置按钮------在早期的网页中它们比较常见,但通常会造成更多困扰。
<button type="button">创建一个普通按钮,其行为和<form>外的按钮一样。需要使用JavaScript来给它们添加功能。
4. 关于无障碍的小提示
5. 其他控件类型
html
<form action="./payment_page" method="get">
<h2>报名参见见面会</h2>
<fieldset>
<legend>选择酒店房型:</legend>
<div>
<input
type="radio"
id="hotelChoice1"
name="hotel"
value="economy"
checked />
<label for="hotelChoice1">经济型(+$0)</label>
<input type="radio" id="hotelChoice2" name="hotel" value="superior" />
<label for="hotelChoice2">高级型(+$50)</label>
<input
type="radio"
id="hotelChoice3"
name="hotel"
value="penthouse"
disabled />
<label for="hotelChoice3">顶级套房(+$150)</label>
</div>
</fieldset>
<fieldset>
<legend>要参加的课程:</legend>
<div>
<input type="checkbox" id="yoga" name="yoga" />
<label for="yoga">瑜伽(+$10)</label>
<input type="checkbox" id="coffee" name="coffee" />
<label for="coffee">咖啡烘焙(+$20)</label>
<input type="checkbox" id="balloon" name="balloon" />
<label for="balloon">气球动物艺术(+$5)</label>
</div>
</fieldset>
<p>
<label for="transport">出行方式:</label>
<select name="transport" id="transport">
<option value="">--请选择一项--</option>
<option value="plane">乘坐飞机</option>
<option value="bike">骑自行车</option>
<option value="walk">徒步</option>
<option value="bus">乘坐公交</option>
<option value="train">搭乘火车</option>
<option value="jetPack">使用喷气背包</option>
</select>
</p>
<p>
<label for="comments">其他备注:</label>
<textarea id="comments" name="comments" rows="5" cols="33"></textarea>
</p>
<p>
<button>去结账</button>
</p>
</form>

5.1 单选按钮
单选按钮是通过<input type="radio">控件来实现的。这些控件会渲染为一组按钮控件,每次只能选择其中一个------你不能同时选中多个。
单选按钮部分:
html
<fieldset>
<legend>选择酒店房型:</legend>
<div>
<input
type="radio"
id="hotelChoice1"
name="hotel"
value="economy"
checked />
<label for="hotelChoice1">经济型(+$0)</label>
<input type="radio" id="hotelChoice2" name="hotel" value="superior" />
<label for="hotelChoice2">高级型(+$50)</label>
<input
type="radio"
id="hotelChoice3"
name="hotel"
value="penthouse"
disabled />
<label for="hotelChoice3">顶级套房(+$150)</label>
</div>
</fieldset>
radio输入控件的工作方式大致和text输入控件相同,但也有极点不同:
每组单选按钮的name属性值必须相同,以便将它们关联成一组。如果name属性值不同,它们会被视为不同的组,提交时也会有发送不同的值。
每个单选按钮必须包含一个value属性,用于指定提交时该按钮对应的值。提交的数据会是一个名值对,其中名称始终相同。
每个单选按钮的<label>应该描述该具体选项的值,而不是你正在选择的这一组选项所代表的字段含义。描述整组选项的推荐做法是使用<fieldset>元素包裹这些选项,并用其子元素<legend>来提供整体描述。
为第一个单选按钮添加了checked属性------这会让它在页面初次加载时默认被选中。这意味着总会有一个选项被选中,并且你无法取消选中一个单选按钮,除非选择另一个。
5.1.1 禁用表单控件
第三个单选按钮设置了disabled属性。这会导致该控件显示为灰色且无法被选中。这在很多情况下都非常有用,比如某个选项通常是可用的,但目前暂时不可用。
可以在任何表单控件上设置disabled属性,包括<button>元素。<fieldset>元素可以接受disabled属性------这会导致该<fieldset>内的所有表单控件都被禁用。
给两个<fieldset>设置disabled属性后:

5.2 复选框
复选框是使用<input type="checkbox">控件实现的。这些控件渲染为一组开关状态的复选框。可以同时选择多个选项。
复选框部分:
html
<fieldset>
<legend>选择要参加的课程:</legend>
<div>
<input type="checkbox" id="yoga" name="yoga" />
<label for="yoga">瑜伽(+$10)</label>
<input type="checkbox" id="coffee" name="coffee" />
<label for="coffee">咖啡烘焙(+$20)</label>
<input type="checkbox" id="balloon" name="balloon" />
<label for="balloon">气球动物艺术(+$5)</label>
</div>
</fieldset>
复选框和单选按钮的实现方式相似,它们都可以使用checked属性,在页面加载时默认被选中。它们的行为也比较类似,不同点在于单选按钮允许你从多个选项中选择零个或一个,而复选框允许你从多个选项中选择零个或多个。
主要区别在于每个复选框的name属性值不同,且通常没有设置value属性。这意味着,每个复选框代表不同的数据值,而单选按钮只代表一个值。当表单提交时,如果复选框被选中,则提交的值为on,例如yoga=on等。
可以通过为复选框添加value属性来自定义提交的值。比如<input type="checkbox" id="yoga" name="yoga" value="yes" />被选中时,会提交yoga=yes。
5.3 下拉菜单
下拉菜单是使用<select>和<option>元素来实现的。
下拉菜单部分:
html
<label for="transport">出行方式:</label>
<select name="transport" id="transport">
<option value="">--请选择一项--</option>
<option value="plane">乘坐飞机</option>
<option value="bike">骑自行车</option>
<option value="walk">徒步</option>
<option value="bus">乘坐公交</option>
<option value="train">搭乘火车</option>
<option value="jetPack">使用喷气背包</option>
</select>
<select>元素包括了所有不同的选项。需要在这里设置id属性,将控件与其标签关联起来,同时设置name属性,指定提交时数据项的名称。
数据项的每个可能值由嵌套在<select>内的<option>元素表示。每个<option>元素可以带有value属性,指定如果该选项被选中时提交的值。如果未指定value,则使用<option></option>标签内的文本内容作为提交值。
3.4 多行文本输入框
多行文本输入框使用<textarea>元素创建:
html
<label for="comments">其他备注:</label>
<textarea id="comments" name="comments" rows="5" cols="33"></textarea>
它们的行为与<input type="text">元素类似,不同之处在于它们允许输入多行文本。rows属性指定文本区域默认显示的行数,而cols属性指定文本区域默认显示的列数。如果未指定这两个属性,浏览器默认使用cols="20"和rows="20"。
大多数浏览器会在文本区域的一个角落显示一个拖拽手柄,可以用来调整文本区域的大小。
6. 表单验证
&meps;前面提到了required属性用于指定某个字段必须填写,才能提交表单;它还会检查某些特定类型的字段是否输入了正确的值。表单验证之所以重要,主要有两个原因:
确保提交的数据格式正确,从而避免在应用程序中引发错误。
防止数据引发安全问题。恶意用户可能会提交特意构造的数据,在不安全的应用中,这些数据可能会执行删除数据库或控制系统等命令。
表单验证主要有两种类型:
客户端验证:在浏览器端进行,通常进行表单验证属性和JavaScript结合实现。客户端验证可以即时提示用户输入有误,但它并不可靠,不能有效阻止恶意数据。因为用户可以关闭JavaScript或修改客户端代码,从而绕过验证。
服务器端验证:在服务器上进行,使用服务器端所采用的任意语言实现。错误格式的数据可以是意外发送的,也可以是有意而为之。经验法则是:服务器永远不要信任客户端发送的任何数据,以避免由于格式错误的消息而引发漏洞或安全问题。服务器端验证更适合阻止恶意消息,因为服务器端代码更难被纂改。但它无法像客户端验证那样及时给用户反馈,因为数据必须先发送到服务器验证,服务器再把结果返回给用户。
不要只选择客户端验证或服务器端验证------你需要两者结合。你需要客户端验证来为用户的输入提供即时反馈;同时也需要服务器端验证,来确保发送到服务器的消息格式是安全、可处理的。