作用
对象的使用:
-
用一些键值对来模拟一系列表单控件,以便使用
XMLHttpRequest
发送 -
异步上传二进制文件
为什么要模拟表单
传统的传递参数可以通过form
表单,设置action
参数,点击submit
触发提交
<form action="xxxx" method="get" class="form-example">
<input type="text" name="name" id="name" required>
<input type="submit" value="Subscribe!">
</form>
这种提交参数的方式有个缺陷,就是提交后每次页面会刷新
,这样体验不好,还重复加载页面,影响服务器性能,后来有了Ajax
,通过XMLHttpRequest
异步传输数据,实现异步加载功能。而此时FormData可以作为参数的一种结构类型,并且结构和form一致,对于服务器端来说,收到的请求参数都像是表单上触发submit一样的。
var formData = new FormData();
var request = new XMLHttpRequest();
request.open("POST", "http://foo.com/submitform.php");
request.send(formData);
Ajax一定需要使用FormData吗
答案是否定的,可以Ajax不使用FormData
通过前文,我们知道Ajax技术可以替换直接使用表单的用法,然而,表单的提交方式很多,具体来说有四种:
-
使用
POST
方法并将enctype属性设置为application / x-www-form-urlencoded
(默认);Content-Type: application/x-www-form-urlencoded foo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A
-
使用
POST
方法并将enctype属性设置为text / plain
;Content-Type: text/plain foo=bar baz=The first line. The second line.
-
使用
POST
方法并将enctype属性设置为multipart / form-data
;Content-Type: multipart/form-data; boundary=---------------------------314911788813839 -----------------------------314911788813839 Content-Disposition: form-data; name="foo" bar -----------------------------314911788813839 Content-Disposition: form-data; name="baz" The first line. The second line. -----------------------------314911788813839--
-
使用
GET
方法(在这种情况下,enctype属性将被忽略)。
?foo=bar&baz=The%20first%20line.%0AThe%20second%20line.
简单来说,就是表单的Content-Type值会不同,通过表单的method 、enctype等参数决定,而纯Ajax提交表单时,需要手动设置Content-Type值,通过FormDate,可以自动填充。
XMLHttpRequest的实例可以通过两种方式用于提交表单:
-
仅使用AJAX
仅使用AJAX更复杂,但通常更灵活,更强大。手动设置参数:
/* method is POST */ oAjaxReq.open("post", oData.receiver, true); if (oData.technique === 3) { /* enctype is multipart/form-data */ var sBoundary = "---------------------------" + Date.now().toString(16); oAjaxReq.setRequestHeader("Content-Type", "multipart\/form-data; boundary=" + sBoundary); oAjaxReq.sendAsBinary("--" + sBoundary + "\r\n" + oData.segments.join("--" + sBoundary + "\r\n") + "--" + sBoundary + "--\r\n"); }
-
使用FormData API
使用FormData API是最简单,最快的方法,但是具有无法对收集的数据进行字符串化的缺点
。
FormData对象的创建
像创建对象一样来创建
你可以创建一个空的FormData对象,并通过append()方法添加参数
var formData = new FormData();
formData.append("username", "Groucho");
formData.append("accountnum", 123456); // 数字 123456 立即被转化为字符串 "123456"
// HTML file 组件
formData.append("userfile", fileInputElement.files[0]); //fileInputElement对象获取方式 $("#fileID").get(0)
// blob
var content = '<a id="a"><b id="b">hey!</b></a>'; // 构建文件的body
var blob = new Blob([content], { type: "text/xml"});
formData.append("webmasterfile", blob);
var request = new XMLHttpRequest();
request.open("POST", "http://foo.com/submitform.php");
request.send(formData);
注意:append()方法接收file,blob,string,因此当非file和blob时,自动转为string
PS:关于blob对象,只要记住它和file对象在使用上差不多就行了,和file对象唯一的不同就是file对象多了个名字,并且file对象的基础就是blob对象,所以两者在使用上没有什么区别。
通过已有的Form来创建
语法
var formData = new FormData(someFormElement);
例子
var formElement = document.querySelector("form"); //表单对象
var request = new XMLHttpRequest();
request.open("POST", "submitform.php");
request.send(new FormData(formElement)); //获取formData对象,并发送
从表单获取参数后,也可以添加额外参数进去
var formElement = document.querySelector("form"); //表单对象
var formData = new FormData(formElement); //获取formData对象
var request = new XMLHttpRequest();
request.open("POST", "submitform.php");
formData.append("serialnumber", serialNumber++); //添加额外参数
request.send(formData);
上传文件
<form>
表单中含有file
类型的input
<form enctype="multipart/form-data" method="post" name="fileinfo">
<label>Your email address:</label>
<input type="email" autocomplete="on" autofocus name="userid" placeholder="email" required size="32" maxlength="64" /><br />
<label>Custom file label:</label>
<input type="text" name="filelabel" size="12" maxlength="32" /><br />
<label>File to stash:</label>
<input type="file" name="file" required />
<input type="submit" value="Stash the file!" />
</form>
<div></div>
你可以使用下面的代码发送上述表单
var form = document.forms.namedItem("fileinfo");
form.addEventListener('submit', function(ev) {
var oOutput = document.querySelector("div"),
oData = new FormData(form); //直接利用表单构建包含file的FormData
oData.append("CustomField", "This is some extra data");
var oReq = new XMLHttpRequest();
oReq.open("POST", "stash.php", true);
oReq.onload = function(oEvent) {
if (oReq.status == 200) {
oOutput.innerHTML = "Uploaded!";
} else {
oOutput.innerHTML = "Error " + oReq.status + " occurred when trying to upload your file.<br \/>";
}
};
oReq.send(oData);
ev.preventDefault();
}, false);
您还可以将File或Blob直接附加到FormData对象,如下所示:
data.append("myfile", myBlob, "filename.txt");
使用append()方法时,可以使用第三个可选参数在要发送到服务器的Content-Disposition标头中传递文件名。 如果未指定文件名(或不支持该参数),则使用名称“ blob”。
常用方法
append
语法
formData.append(name, value);
formData.append(name, value, filename);
name
value中包含的数据对应的表单名称。value
表单的值。可以是USVString 或 Blob (包括子类型,如 File)。filename
可选
传给服务器的文件名称 (一个 USVString), 当一个 Blob 或 File 被作为第二个参数的时候, Blob 对象的默认文件名是 “blob”。 File 对象的默认文件名是该文件的名称。
示例
formData.append('username', 'Chris');
formData.append('userpic', myFileInput.files[0], 'chris.jpg');
跟常规表单数据一样,你可以使用同一个名称添加多个值 。例如 (为了与PHP命名习惯一致在名称中添加了[]):
formData.append('userpic[]', myFileInput1.files[0], 'chris1.jpg');
formData.append('userpic[]', myFileInput2.files[0], 'chris2.jpg');
这项技术使得多文件上传的处理更加简单,因为所得数据结构更有利于循环。