表单和FormData 对象
【表单和FormData 对象】
FormData 对象
概述
表单数据以键值对的形式向服务器发送,这个过程是浏览器自动完成的。但是有时候,我们希望通过脚本完成这个过程,构造或编辑表单的键值对,然后通过脚本发送给服务器。浏览器原生提供了 FormData 对象来完成这项工作。
FormData()
首先是一个构造函数,用来生成表单的实例。
1 | var formdata = new FormData(form); |
FormData()
构造函数的参数是一个 DOM 的表单元素,构造函数会自动处理表单的键值对。这个参数是可选的,如果省略该参数,就表示一个空的表单。
下面是一个表单。
1 | <form id="myForm" name="myForm"> |
我们用FormData()
处理上面这个表单。
1 | var myForm = document.getElementById('myForm'); |
实例方法
FormData 提供以下实例方法。
FormData.get(key)
:获取指定键名对应的键值,参数为键名。如果有多个同名的键值对,则返回第一个键值对的键值。FormData.getAll(key)
:返回一个数组,表示指定键名对应的所有键值。如果有多个同名的键值对,数组会包含所有的键值。FormData.set(key, value)
:设置指定键名的键值,参数为键名。如果键名不存在,会添加这个键值对,否则会更新指定键名的键值。如果第二个参数是文件,还可以使用第三个参数,表示文件名。FormData.delete(key)
:删除一个键值对,参数为键名。FormData.append(key, value)
:添加一个键值对。如果键名重复,则会生成两个相同键名的键值对。如果第二个参数是文件,还可以使用第三个参数,表示文件名。FormData.has(key)
:返回一个布尔值,表示是否具有该键名的键值对。FormData.keys()
:返回一个遍历器对象,用于for...of
循环遍历所有的键名。FormData.values()
:返回一个遍历器对象,用于for...of
循环遍历所有的键值。FormData.entries()
:返回一个遍历器对象,用于for...of
循环遍历所有的键值对。如果直接用for...of
循环遍历 FormData 实例,默认就会调用这个方法。
下面是get()
、getAll()
、set()
、append()
方法的例子。
1 | var formData = new FormData(); |
下面是遍历器的例子。
1 | var formData = new FormData(); |
表单的内置验证
自动校验
表单提交的时候,浏览器允许开发者指定一些条件,它会自动验证各个表单控件的值是否符合条件。
1 | <!-- 必填 --> |
如果一个控件通过验证,它就会匹配:valid
的 CSS 伪类,浏览器会继续进行表单提交的流程。如果没有通过验证,该控件就会匹配:invalid
的 CSS 伪类,浏览器会终止表单提交,并显示一个错误信息。
1 | input:invalid { |
checkValidity()
除了提交表单的时候,浏览器自动校验表单,还可以手动触发表单的校验。表单元素和表单控件都有checkValidity()
方法,用于手动触发校验。
1 | // 触发整个表单的校验 |
checkValidity()
方法返回一个布尔值,true
表示通过校验,false
表示没有通过校验。因此,提交表单可以封装为下面的函数。
1 | function submitForm(action) { |
setCustomValidity()
控件元素的setCustomValidity()
方法用来定制校验失败时的报错信息。它接受一个字符串作为参数,该字符串就是定制的报错信息。如果参数为空字符串,则上次设置的报错信息被清除。
这个方法可以替换浏览器内置的表单验证报错信息,参数就是要显示的报错信息。
1 | <form action="somefile.php"> |
上面的表单输入框,要求只能输入小写字母,且不得超过15个字符。如果输入不符合要求(比如输入“ABC”),提交表单的时候,Chrome 浏览器会弹出报错信息“Please match the requested format.”,禁止表单提交。下面使用setCustomValidity()
方法替换掉报错信息。
1 | var input = document.getElementById('username'); |
上面代码中,setCustomValidity()
方法是在invalid
事件的监听函数里面调用。该方法也可以直接调用,这时如果参数不为空字符串,浏览器就会认为该控件没有通过校验,就会立刻显示该方法设置的报错信息。
1 | /* HTML 代码如下 |
上面代码一旦发现文件大于 75KB,就会设置校验失败,同时给出自定义的报错信息。然后,点击提交按钮时,就会显示报错信息。这种校验失败是不会自动消除的,所以如果所有文件都符合条件,要将报错信息设为空字符串,手动消除校验失败的状态。
表单的 novalidate 属性
表单元素的 HTML 属性novalidate
,可以关闭浏览器的自动校验。
1 | <form novalidate> |
这个属性也可以在脚本里设置。
1 | form.noValidate = true; |
如果表单元素没有设置novalidate
属性,那么提交按钮(<button>
或<input>
元素)的formnovalidate
属性也有同样的作用。
1 | <form> |
enctype 属性
表单能够用四种编码,向服务器发送数据。编码格式由表单的enctype
属性决定。
假定表单有两个字段,分别是foo
和baz
,其中foo
字段的值等于bar
,baz
字段的值是一个分为两行的字符串。
1 | The first line. |
下面四种格式,都可以将这个表单发送到服务器。
(1)GET 方法
如果表单使用GET
方法发送数据,enctype
属性无效。
1 | <form |
数据将以 URL 的查询字符串发出。
1 | ?foo=bar&baz=The%20first%20line.%0AThe%20second%20line. |
(2)application/x-www-form-urlencoded
如果表单用POST
方法发送数据,并省略enctype
属性,那么数据以application/x-www-form-urlencoded
格式发送(因为这是默认值)。
1 | <form |
发送的 HTTP 请求如下。
1 | Content-Type: application/x-www-form-urlencoded |
上面代码中,数据体里面的%0D%0A
代表换行符(\r\n
)。
(3)text/plain
如果表单使用POST
方法发送数据,enctype
属性为text/plain
,那么数据将以纯文本格式发送。
1 | <form |
发送的 HTTP 请求如下。
1 | Content-Type: text/plain |
(4)multipart/form-data
如果表单使用POST
方法,enctype
属性为multipart/form-data
,那么数据将以混合的格式发送。
1 | <form |
发送的 HTTP 请求如下。
1 | Content-Type: multipart/form-data; boundary=---------------------------314911788813839 |
这种格式也是文件上传的格式。
文件上传
用户上传文件,也是通过表单。具体来说,就是通过文件输入框选择本地文件,提交表单的时候,浏览器就会把这个文件发送到服务器。
1 | <input type="file" id="file" name="myFile"> |
此外,还需要将表单<form>
元素的method
属性设为POST
,enctype
属性设为multipart/form-data
。其中,enctype
属性决定了 HTTP 头信息的Content-Type
字段的值,默认情况下这个字段的值是application/x-www-form-urlencoded
,但是文件上传的时候要改成multipart/form-data
。
1 | <form method="post" enctype="multipart/form-data"> |
上面的 HTML 代码中,file 控件的multiple
属性,指定可以一次选择多个文件;如果没有这个属性,则一次只能选择一个文件。
1 | var fileSelect = document.getElementById('file'); |
然后,新建一个 FormData 实例对象,模拟发送到服务器的表单数据,把选中的文件添加到这个对象上面。
1 | var formData = new FormData(); |
最后,使用 Ajax 向服务器上传文件。
1 | var xhr = new XMLHttpRequest(); |
除了发送 FormData 实例,也可以直接 AJAX 发送文件。
1 | var file = document.getElementById('test-input').files[0]; |