
上次说完了图片上传预览,使用form提交就可以把图片进行提交了,但是在现实中这样的操作往往满足不了用户需求,一般在进行上传操作时可能会进行图片的多次重新选择和增删所选择的图片,这时用form提交就实现不了。
W3C在2008年提出XMLHttpRequest Level 2的草案中改进了XMLHttpRequest对象,在新版本的一些功能中就有FormData。利用FormData对象,我们可以模拟表单操作,然后通过XMLHttpRequest的send()方法来异步提交这个表单,发送FormData对象,这与form提交网页表单的效果完全一样,这个改进使得可以通过新版XMLHttpRequest对象上传文件,使得无刷新上传文件成为了可能。
1.FormData
创建一个FormData对象,可以直接通过new FormData()创建一个FormData空对象:
1
| var formData = new FormData();
|
当然,想要构造一个包含Form表单数据的FormData对象时,也可以通过HTML表单创建FormData对象,需要在创建FormData对象时指定表单的元素,这样做在发送数据时会将你的form表单的数据添加到formData中一起发送出去。
1 2
| var myform = document.querySelector("form"); var formData = new FormData(myform);
|
2.FormData操作方法
FormData通过append(name, value,filename)来添加数据,其实就是类似于使用键值对添加数据,如果添加的name不存在则会新增一条数据,如果name已存在,则value将添加到数组的末尾,类似于[‘a1’,’a2’]。filename是可选的,这是指定文件的文件名,当value参数被指定为一个Blob对象或者一个File对象时,该文件名会被发送到服务器上,对于Blob对象来说,这个值默认为blob。
1 2 3 4 5
| formData.append("a1", "aa"); formData.append("a1", "bb"); formData.append("a1", "cc"); formData.getAll("a1"); // ["aa","bb","cc"]
|
set(name, value) 方法会对 FormData 对象里的某个 name 设置一个新的value,如果该 name 不存在,则添加。
1 2 3
| formData.append("a1", "aa"); formData.set("a1","bb"); formData.get("a1");
|
delete() 方法 会从 FormData 对象中删除指定 name 和它对应的 value。
1 2 3
| formData.append("a1", "aa"); formData.delete("a1"); formData.get("a1");
|
get()和getAll(),get()方法用于返回FormData对象中和指定的键关联的第一个值,getAll()方法会返回该 FormData 对象指定键的所有值。
1 2 3 4 5 6
| formData.append("a1", "aa"); formData.append("a1", "bb"); formData.append("a1", "cc"); formData.get("a1"); // "aa" formData.getAll("a1"); // ["aa","bb","cc"]
|
has()方法会返回一个布尔值,表示该FormData对象是否含有某个name 。
1 2
| formData.append("a1", "aa"); formData.has("a1");
|
当然还有遍历,entries()遍历所有的数据,keys()遍历所有key,values()遍历所有value,用法都一样
1 2 3 4 5
| formData.append('a', 'aa'); formData.append('b', 'bb'); for(var pair of formData.entries()) { console.log(pair[0]+ ', '+ pair[1]); }
|
好了,废话说了这么多,该进入正题了。
想要对用户选择的图片进行准确的上传,用什么方式最简单呢?当然是用数组进行操作啦。
首先来个上传多文件上传input
1
| <input type="file" class="hidden" id="file" multiple="multiple"/>
|
然后声明一个空数组,在onchang事件发生时把用户要上传的图片装进去
1 2 3 4 5 6 7 8 9 10
| var filearr = []; var myfile = document.getElementById('file'); myfile.onchange = function(){ var files = this.files; if(!files.length)return; for(var i = 0;i<files.length;i++){ filearr.push(files[i]); } }
|
当用户删除图片时(.close是删除按钮,closeli()是.close点击时执行的函数),filearr也进行删除,预览用的图片也要干掉,当然数据结构不同时自行处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <li><img src=""><span class="close" onclick="closeli(this)">×</span></li> var closes = document.getElementsByClassName("close"); function closeli(obj){ var closes = document.getElementsByClassName("close"); [].slice.call(closes).forEach(function(el,index){ if(obj === closes[index]){ filearr.splice(index,1); }; }); parents(obj,'li').remove(); } function parents(obj,node){ if(obj.parentNode.tagName==node.toUpperCase()){ return obj.parentNode; }else{ return parents(obj.parentNode,node); } }
|
点击上传时,如果要连form表单中的数据一起提交就把form传入FormData中,否则可以创建一个FormData空对象提交,当然你也可以通过append添加自定义数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function sub(){ var myform = document.querySelector("form"); var formData = new FormData(myform); for(var i =0;i<filearr.length;i++){ formData.append("upfile[]", filearr[i]); }; formData.append("aaa", 111); var request = new XMLHttpRequest(); request.open("POST", "1.php",true); request.onreadystatechange = function(){ if(request.readyState==4){ } }; request.send(formData); }
|
可以用1.php看看上传的数据
1 2 3 4
| <?php var_dump($_FILES); var_dump($_REQUEST); ?>
|

当然,你如果用的是jq的话,ajax得改一改。processData设置为false,因为data值是FormData对象,不需要对数据做处理;contentType设置为false,因为上传的是FormData对象,不需要设置内容类型;当然上传文件不需要缓存,cache:false。
1 2 3 4 5 6 7 8 9 10
| function sub(){ $.ajax({ url: "1.php", type: "POST", data:formData, cache:false, //不设置缓存 processData: false, // 不处理数据 contentType: false // 不设置内容类型 }); }
|
由于本文在github上的,做不了服务器演示,故不能成功提交,想看提交数据的自行打开浏览器的notwork查看:
ok,图片上传就算是完成了,当然本人原创内容,能力有限,才疏学浅,有错误的地方望大家指正。下次更新文件上传时的一些杂项,比如美化上传按钮,显示上传进度什么的。请期待:请期待:图片上传那些事-总结篇。
本文代码地址:链接