HTML表单
本笔记记于2021年,摘自MDN HTML板块
1.HTML表单是什么
HTML表单是用户和web站点或应用程序之间交互的主要内容之一
允许用户将数据发送到web站点
大多数情况下,数据被发送到web服务器,但是web页面也可以自己拦截并使用
2.用HTML实现表单
form是一个容器元素,但它也支持一些特定的属性来配置表单的行为方式
所有属性都是可选的,最好至少要设置action属性和method属性
- action 属性定义了在提交表单时,应该把所收集的数据送给谁(/那个模块)(URL)去处理
- method 属性定义了发送数据的HTTP方法(它可以是“get”或“post”)
<label>
元素上使用for
属性;它是将标签链接到表单小部件的一种正规方式,引用对应的小部件的id,允许用户单击标签以激活相应的小部件
在
<input>元素中
type
属性,定义了<input>
属性的行为方式,可从根本上改变元素
-
text
,type属性的默认值
表示一个基本的单行文本字段,接受任何类型的文本输入 -
email
,它定义了一个只接受格式正确的电子邮件地址的单行文本字段
要定义<input>
的默认值,必须使用value
属性
想定义<textarea>
的默认值,只需在<textarea>
元素的开始和结束标记之间放置默认值
<button>
元素也接受一个 type
属性,接受submit
, reset
或者 button
三个值中的任一个
-
submit
:(也是默认值)会发送表单的数据到<form>
元素的action
属性所定义的网页 -
reset
:将所有表单小部件重新设置为它们的默认值 -
button
:用JavaScript构建定制按钮
向web服务器发送表单数据:
<form>
元素将定义如何通过action
属性和method
属性来发送数据的位置和方式
要将数据命名为表单,需要在每个表单小部件上使用 name 属性来收集特定的数据块
3.构造HTML表单
严格禁止在一个表单内嵌套另一个表单,嵌套会使表单的行为不可预知
<fieldset>
元素是一种方便的用于创建具有相同目的的小部件组的方式,出于样式和语义目的
可以在<fieldset>
开口标签后加上一个 <legend>
元素来给<fieldset>
标上标签 <legend>
的文本内容正式地描述了<fieldset>
里所含有部件的用途
一般来说,<fieldset>
元素也可以用来对表单进行分段
理想情况下,长表单应该在拆分为多个页面,但是如果表单很长,却必须在单个页面上,那么将以不同的关联关系划分的分段,分别放在不同的fieldset里,可以提高可用性
<label>
元素是为HTML表单小部件定义标签的正式方法
<label>
标签与<input>
通过他们各自的for 属性和 id 属性正确相关联(label的for属性和它对应的小部件的id属性)
<label for="name">Name:</label> <input type="text" id="name" name="user_name">
一个小部件可以嵌套在它的<label>
元素中
<label for="name">
Name: <input type="text" id="name" name="user_name">
</label>
正确设置标签的另一个好处是可以在所有浏览器中单击标签来激活相应的小部件
这对于像文本输入这样的例子很有用,可通过点击标签,和点击输入区效果一样,来聚焦于它,这对于单选按钮和复选框尤其有用——这种控件的可点击区域可能非常小,设置标签来使它们可点击区域变大是非常有用的
<p>
元素也经常被使用在构造多个复选框或单选按钮
4.原生表单部件
(1)通用属性
通用属性(2)文本输入框(type="text")
文本输入框 <input>
是最基本的表单小部件
这是一种非常方便的方式,可以让用户输入任何类型的数据
通用规范:
- 它们可以被标记为
readonly
(用户不能修改输入值)甚至是disabled
(输入值永远不会与表单数据的其余部分一起发送) - 它们可以有一个
placeholder
; 这是文本输入框中出现的文本,用来简略描述输入框的目的 - 它们可以被限制在
size
(框的物理尺寸) 和maxlength
(可以输入的最大字符数) - 如果浏览器支持的话,他们可以从拼写检查中获益
使用type
属性值被设置为text
的<input>
元素创建一个单行文本框(同样的,如果不提供type
属性,text
是默认值)
单行文本框只有一个真正的约束:如果输入带有换行符的文本,浏览器会在发送数据之前删除这些换行符
(3)E-mail地址框(type="email")
通过包括multiple
属性,它还可以让用户将多个电子邮件地址输入相同的输入(以逗号分隔)
当使用 type时, 用户需要在框中输入有效的电子邮件地址;任何其他内容都会导致浏览器在提交表单时显示错误
(4)密码框(type="password")
它不会为输入的文本添加任何特殊的约束,但是它会模糊输入到字段中的值(例如,用点或小行星),这样它就不能被其他人读取
这只是一个用户界面特性;除非安全地提交表单,否则它会以明文发送,这不利于安全——恶意的一方可能会截获数据,窃取密码、信用卡信息,或者提交的其他任何东西
保护用户不受此影响的最佳方式是在安全连接上托管任何涉及表单的页面(例如:https://……地址),使得数据在发送之前就已加密
(5)搜索框(type="search")
文本框和搜索框之间的主要区别是浏览器的样式——通常,搜索框是渲染成圆角的,并且/可能给定一个“x”来清除输入的值
然而,还有另外一个值得注意的特性:它们的值可以被自动保存用来在同一站点上的多个页面上自动补全
(6)电话号码栏(type="tel")
由于世界范围内各种各样的电话号码格式,这种类型的字段不会对用户输入的值执行任何限制(包括字母,等等)
这主要是在语义上的区分,尽管在一些设备上(特别是在移动设备上),可能会出现一个不同的虚拟键盘,更适合输入电话号码
(7)URL栏(type="url")
它为字段添加了特殊的验证约束,如果输入无效的url,浏览器就会报告错误
URL格式良好并不一定意味着它引用了一个实际存在的位置
(8)多行文本框
多行文本框专指使用 <textarea>
元素,而不是使用<input>
元素
textarea和常规的单行文本字段之间的主要区别是,允许用户输入包含硬换行符(即按回车)的文本
<input>
元素是一个空元素,这意味着它不能包含任何子元素另一方面,
<textarea>
元素是一个常规元素,可以包含文本内容的子元素
- 如果为
<input>
元素定义一个默认值,那么必须使用value
属性;另一方面,对于<textarea>
元素,只需要将默认的文本放在起始标记和<textarea>
的结束标记之间 - 因为它的本质,
<textarea>
元素只接受文本内容;这意味着将任何HTML内容放入<textarea>
中都呈现为纯文本内容
(9)下拉内容
一个选择框是用<select>
元素创建的,其中有一个或多个<option>
元素作为子元素,每个元素都指定了其中一个可能的值
如果需要,可以使用selected
属性在所需的<option>
元素上设置选择框的默认值---在页面加载时会默认选择该选项<option>
元素也可以嵌套在<optgroup>
元素中,以创建视觉关联的组值
<select id="groups" name="groups">
<optgroup label="fruits">
<option>Banana</option>
<option selected>Cherry</option>
<option>Lemon</option>
</optgroup>
<optgroup label="vegetables">
<option>Carrot</option>
<option>Eggplant</option>
<option>Potato</option>
</optgroup>
</select>
如果一个<option>元素设置了value属性,那么当提交表单时该属性的值就会被发送
如果忽略了value属性,则使用<option>元素的内容作为选择框的值
在<optgroup>元素中,label属性显示在值之前,但即使它看起来有点像一个选项,它也不是可选的
默认情况下,选择框只允许用户选择一个值
通过将multiple属性添加到<select>元素,可允许用户通过操作系统提供的默认机制来选择几个值
可以使用<datalist>元素来为表单小部件提供建议的、自动完成的值,并使用一些<option>子元素来指定要显示的值
然后使用list属性将数据列表绑定到一个文本框(通常是一个 <input> 元素)
<label for="myFruit">What's your favorite fruit?</label>
<input type="text" name="myFruit" id="myFruit" list="mySuggestion">
<datalist id="mySuggestion">
<option>Apple</option>
<option>Banana</option>
<option>Blackberry</option>
<option>Blueberry</option>
<option>Lemon</option>
<option>Lychee</option>
<option>Peach</option>
<option>Pear</option>
</datalist>
<datalist>元素版本小于10的IE中不受支持,同时在版本小于12的Safari中不受支持
(10)可选中项:有两种可选中项:复选框和单选按钮,只有在勾选时才发送它们的值
使用type属性值为checkbox的 <input>元素来创建一个复选框
使用type属性值为radio的 <input>元素来创建一个单选按钮
(11)按钮
在HTML表单中,有三种按钮:
- Submit
将表单数据发送到服务器
对于<button> 元素, 省略 type 属性 (或是一个无效的 type 值) 的结果就是一个提交按钮. - Reset
将所有表单小部件重新设置为它们的默认值 - Anonymous
没有自动生效的按钮,但是可以使用JavaScript代码进行定制
<button>元素允许在它们的标签中使用HTML内容,这些内容被插入到打开和关闭<button> 标签中
另一方面,<input>元素是空元素;它们的标签插入在value属性中,因此只接受纯文本内容
使用<button>元素,可以有一个不同于按钮标签的值(通过设置value中的属性值)
这在IE 8之前的版本中是不可靠的
从技术上讲,使用<button>元素或<input>元素定义的按钮几乎没有区别
唯一值得注意的区别是按钮本身的标签
在<input>元素中,标签只能是字符数据,而在<button>元素中,标签可以是HTML,因此可以相应地进行样式化
5.高级表单
(1)数字
用于数字的小部件是用type属性设置为number<input>的元素创建的
这个控件看起来像一个文本框,但是只允许浮点数,并且通常提供一些按钮来增加或减少小部件的值
- 通过设置
min
和max
属性来约束该值 - 通过设置
step
属性来指定增加和减少按钮更改小部件的步进值大小
(2)滑块
滑块是通过把<input>元素的type属性值设置为range来创建的
正确配置滑块是很重要的;为了达到这个目的,最好设置min、max和step属性
滑块的一个问题是,它们不提供任何形式的视觉反馈,以了解当前的值是什么
需要使用JavaScript来添加这一点,但这相对来说比较容易
在10以下的Internet Explorer版本中不支持range
(3)时间选择器
所有日期和时间控制都可以使用min和max属性来约束
警告——日期和时间窗口小部件仍然很不受支持
目前,Chrome、Edge和Opera都支持它们,但IE浏览器没有支持,Firefox和Safari对这些都没有太大的支持
(4)拾色器
一个颜色小部件是使用type属性设置为值color<input>的元素创建的
(5)文件选择器
要创建一个文件选择器小部件,<input>元素的type属性设置为file
被接受的文件类型可以使用accept属性来约束
选择多个文件,那么可以通过添加multiple属性来实现
(6)隐藏内容
由于为了方便技术原因,有些数据是用表单发送的,但不显示给用户
要做到这一点,可以在表单中添加一个不可见的元素
要做到这一点,需要使用<input>将它的type属性设置为hidden值
(7)图像按钮
当用户点击它时,它的行为就像一个提交按钮(见上面)
图像按钮是使用type属性值设置为image<input>的元素创建的
这个元素支持与<img>元素相同的属性,和其他表单按钮支持的所有属性
如果使用图像按钮来提交表单,这个小部件不会提交它的值;相反,提交的是在图像上单击处的X和Y坐标(坐标是相对于图像的,这意味着图像的左上角表示坐标0,0),坐标被发送为两个键/值对:
X值键是name属性的值,后面是字符串“.x”
Y值键是name属性的值,后面是字符串“.y”
构建“热图”的一种非常方便的方式
(8)进度条
<progress>元素中的内容用于不支持该元素的浏览器的回退,以及辅助技术对其朗读
(9)仪表
- low 和 high 值范围划分为三个部分:
该范围的较低部分是在min和low值(包括那些值)之间
该范围的中间部分是在low和high值之间(不包括那些值)
该范围的较高部分是在high和max值(包括那些值)之间 - optimum值定义了<meter>元素的最优值
在与htmlattrxref(“low”、“meter”)和high值的联合中,它定义了该范围的哪个部分是优先的:
如果optimum值在较低的范围内,则较低的范围被认为是首选项,中等范围被认为是一般的,而较高的范围被认为是最坏的部分
如果optimum值在该范围的中等部分,则较低的范围被认为是一个一般的,中等范围被认为是优先的部分,而较高的范围也被认为是平均值
如果optimum值在较高的范围内,则较低的范围被认为是最坏的部分,中等范围被认为是一般的部分,较高的范围被认为是优先的部分
所有实现<meter>元素的浏览器都使用这些值来改变米尺的颜色
如果当前值位于该范围的优先部分,则该条是绿色的
如果当前值位于该范围的平均部分,则该条是黄色的
如果当前值处于最糟糕的范围,则该条是红色的
<meter min="0" max="100" value="75" low="33" high="66" optimum="50">75</meter>
<meter>元素中的内容是不支持该元素的浏览器的回退,以及辅助技术对其发出的声音
对进度条和仪表的支持是相当不错的,在Internet Explorer中没有支持,但是其他浏览器都可以很好的支持它
6.样式化HTML表单
在1995年左右的Web早期,表单组件(或控件)在 HTML 2规范中被添加到HTML
由于表单组件的复杂性,实现者选择依靠底层操作系统来管理和渲染它们
有些元素根本不能用应用CSS样式
这些包括:所有高级用户界面小部件,如范围,颜色或日期控件; 和所有下拉小部件,包括<select>, <option>, <optgroup>和<datalist> 元素
文件选择器小部件也被称为不可样式化
新的<progress>和<meter> 元素也属于这个类别
搜索框是唯一一种应用CSS样式有点棘手的文本字段
在基于WebKit的浏览器(Chrome,Safari等)上,必须使用-webkit-appearance专有属性来调整它
为了让form表单的外观和其他内容保持一致,可在样式表中增加以下内容:
button, input, select, textarea {
font-family : inherit;
font-size : 100%;
}
因为每个小部件都有自己的边框,填充和边距的规则
所以如果想给几个不同的小部件相同的大小,必须使用box-sizing 属性
input, textarea, select, button {
width : 150px;
margin: 0;
-webkit-box-sizing: border-box; /* For legacy WebKit based browsers */
-moz-box-sizing: border-box; /* For legacy (Firefox <29) Gecko based browsers */
box-sizing: border-box;
}
添加outline 属性非常重要,这样可以移除由某些浏览器添加的默认高亮效果:
单行文本需要一些调整才能在 Internet Explorer 中渲染良好
Internet Explorer 没有基于字体的自然高度来定义文本域的高度(而这是所有其他浏览器都有的行为)
为了修正这个问题,我们需要给域添加一个确定的高度,像下面这样:
input {
height: 2.5em; /* for IE */
vertical-align: middle; /* This is optional but it makes legacy IEs look better */
}
<textarea> 元素默认地被渲染成一个块级元素
这里有重要地两点是 resize 和 overflow 属性
因为我们的设计是一个固定大小的设计,所以使用 resize 属性来防止用户调整我们的多行文本域的大小
overflow 属性是用来让域在不同的浏览器上渲染得更一致
一些浏览器默认值为 auto,而一些将默认值设为 scroll
在例子中,最好确定每个浏览器都使用 auto
textarea {
display : block;
padding : 10px;
margin : 10px 0 0 -10px;
width : 340px;
height : 360px;
resize : none;
overflow: auto;
}
7.高级设计表单样式
CSS表现力8.表单数据校验
表单校验 —— 向 Web 应用输入数据时,应用会验证输入的数据是否是正确的
如果验证通过,应用允许提交这些数据到服务器并储存到数据库中(通常情况下),如果验证未通过,则 Web 应用会提示有错误的数据,并且一般都会明确的告诉错误发生在哪里
表单校验可以通过许多不同的方式实现
三个最主要的原因:
- 我们希望以正确的格式获取到正确的数据 —— 如果我们的用户数据以不正确的格式存储,或者他们没有输入正确的信息/完全省略信息,我们的应用程序将无法正常运行
- 我们希望保护我们的用户 ——强制用户输入安全的密码,有利于保护他们的账户信息
- 我们希望保护我们自己 —— 恶意用户有很多通过滥用应用中缺乏保护的表单破坏应用的方法(具体请参见网站安全)
不同的表单校验:
客户端校验发生在浏览器端,表单数据被提交到服务器之前,这种方式相较于服务器端校验来说,用户体验更好,它能实时的反馈用户的输入校验结果,这种类型的校验可以进一步细分成下面这些方式:
JavaScript 校验,这是可以完全自定义的实现方式;
HTML5 内置校验,这不需要 JavaScript ,而且性能更好,但是不能像JavaScript那样可自定义
服务器端校验则是发生在浏览器提交数据并被服务器端程序接收之后 —— 通常服务器端校验都是发生在将数据写入数据库之前,如果数据没通过校验,则会直接从服务器端返回错误消息,并且告诉浏览器端发生错误的具体位置和原因,服务器端校验不像客户端校验那样有好的用户体验,因为它直到整个表单都提交后才能返回错误信息
但是服务器端校验是应用对抗错误/恶意数据的最后防线,在这之后,数据将被持久化至数据库
当今所有的服务端框架都提供了数据校验与清洁功能(让数据更安全)
在真实的项目开发过程中,开发者一般都倾向于使用客户端校验与服务器端校验的组合校验方式以更好的保证数据的正确性与安全性
(1)required属性
required属性 — 如果要使输入成为必需的,则可以使用此属性标记元素
当设置此属性时,如果输入为空,该表单将不会提交(并将显示错误消息),输入也将被视为无效
(2)正则表达式
校验功能是 pattern 属性, 以 Regular Expression 作为 value 值. 正则表达式 (regex) 是一个可以用来匹配文本字符串中字符的组合的模式,所以它们是理想的表单校验器,也可以支持 JavaScript 中许多其它的用途
(3)限制输入的长度
所有文本框 (<input> 或 <textarea>) 都可以使用minlength 和 maxlength 属性来限制长度. 如果输入的字段长度小于 minlength 的值或大于 maxlength 值则无效
在数字条目中 (i.e. <input type="number">), 该 min 和 max 属性同样提供校验约束.如果字段的值小于min 属性的值或大于 max 属性的值,该字段则无效
(4)自定义错误信息
在JavaScript 中, 调用 setCustomValidity() 方法:
//HTML
<form>
<label for="mail">I would like you to provide me an e-mail</label>
<input type="email" id="mail" name="mail">
<button>Submit</button>
</form>
//JS
var email = document.getElementById("mail");
email.addEventListener("input", function (event) {
if (email.validity.typeMismatch) {
email.setCustomValidity("I expect an e-mail, darling!");
} else {
email.setCustomValidity("");
}
});
(5)使用JS校验表单
详见文档
表单校验注意事项:
- 显示明确的错误消息
- 放宽输入格式限制
- 指出错误发生的位置(特别是在大型表单中)
9.发送表单数据
<form>元素定义了如何发送数据
它的所有属性都是为了配置当用户点击提交按钮时发送的请求
两个最重要的属性是action和method
action 属性定义了发送数据要去的位置
它的值必须是一个有效的URL
如果没有提供此属性,则数据将被发送到包含这个表单的页面的URL
method属性定义了如何发送数据
HTTP协议提供了几种执行请求的方法;HTML表单数据可以通过许多不同的方法进行数据传输,其中最常见的是GET方法和POST方法
(1)发送文件
用HTML表单发送文件是一个特殊的例子
文件是二进制数据——或者被认为是这样的——而所有其他数据都是文本数据
由于HTTP是一种文本协议,所以处理二进制数据有特殊的要求
enctype 属性允许指定在提交表单时所生成的请求中的Content-Type的HTTP数据头的值
这个数据头非常重要,因为它告诉服务器正在发送什么样的数据
默认情况下,它的值是application/x-www-form-urlencoded
它的意思是:“这是已编码为URL参数的表单数据”
要发送文件,需要额外的三个步骤:
将method属性设置为POST,因为文件内容不能放入URL参数中
将enctype的值设置为multipart/form-data,因为数据将被分成多个部分,每个文件单独占用一个部分,表单正文中包含的文本数据(如果文本也输入到表单中)占用一个部分
包含一个或多个File picker小部件,允许用户选择将要上传的文件
(2)常见安全问题
跨站脚本(XSS)和跨站点请求伪造(CSRF)是常见的攻击类型,它们发生在将用户发送的数据显示给这个用户或另一个用户时
- XSS允许攻击者将客户端脚本注入到其他用户查看的Web页面中
攻击者可以使用跨站点脚本攻击的漏洞来绕过诸如同源策略之类的访问控制 - CSRF攻击类似于XSS攻击,因为它们以相同的方式开始攻击——向Web页面中注入客户端脚本——但它们的目标是不同的CSRF攻击者试图将权限升级到特权用户(比如站点管理员)的级别,以执行他们不应该执行的操作(例如,将数据发送给一个不受信任的用户)
XSS攻击利用用户对web站点的信任,而CSRF攻击则利用网站对其用户的信任 - SQL 注入是一种试图在目标web站点使用的数据库上执行操作的攻击类型
这通常包括发送一个SQL请求,希望服务器能够执行它(通常发生在应用服务器试图存储由用户发送的数据时)
HTTP数据头注入和电子邮件注入,出现在当应用程序基于表单上用户的数据输入构建HTTP头部或电子邮件时
10.构建表单小工具
(1) tabIndex 属性可以确保原生组件将永远不会获得焦点,而且还可以确保当用户用户使用键盘和鼠标时,自定义组件能够获得焦点
(2)ARIA 使用的关键属性是 role 属性
role 属性接受一个值,该值定义了一个元素的用途
每个 role 定义了它自己的需求和行为
ARIA定义了默认应用于标准 HTML 标记的角色
例如,<table> 元素与角色 grid 相匹配,而 <ul> 元素与角色 list 相匹配
由于我们使用了一个 <ul> 元素,我们想要确保我们组件的 listbox 角色能替代 <ul> 元素的list 角色
presentation角色被设计成来表示一个元素没有特殊的含义,并且仅仅用于提供信息
aria-selected 属性被用来标记当前被选中的选项;这可以让辅助技术告知用户当前的选项是什么
通过 JavaScript 动态地使用该属性,每当用户选择一个选项时标记选中的选项
11.使用JS提交表单
三种方式发送表单数据:
- 构建 XMLHttpRequest,XMLHttpRequest 是进行 HTTP 请求的最安全和最可靠的方式
- 使用 XMLHttpRequest 和 the FormData object(表单数据对象)
- 在隐藏的iframe中构建DOM,最古老的异步发送表单数据方法是用 DOM API 构建表单,然后将其数据发送到隐藏的 <iframe>