// 存储更新所选文件 var curFiles = []; ... // 选中文件后 var files = this.files; if (files && files.length) { // 原始FileList对象不可更改,所以将其赋予curFiles提供接下来的修改 Array.prototype.push.apply(curFiles, files); }
假如点击了删除叉叉,可以直接更新文件信息数组
var name = $(this).prev().text(); // 去除该文件 curFiles = curFiles.filter(function(file) { return file.name !== name; });
这样一来,更新文件信息的问题得到解决,然后就可以进行文件的上传了
点击文件上传,如果直接调用$form.submit(); 则上传的文件信息依然是初始的FileList对象,达不到我们自定义的要求,所以需要用Ajax提交
那么,该怎么想后台提供一个文件对象呢?
2)FormData
HTML5引入了表单的新对象FormData, 它可以生成一个表单对象,我们可以向其中获取/设置键值对信息,再一并提交给后台
引用MDN的FormData使用方法,我们可以添加各种类型的数据,使用ajax提交
var oMyForm = new FormData(); oMyForm.append("username", "Groucho"); oMyForm.append("accountnum", 123456); // 数字123456被立即转换成字符串"123456" // fileInputElement中已经包含了用户所选择的文件 oMyForm.append("userfile", fileInputElement.files[0]); var oFileBody = '<a><b>hey!</b></a>'; // Blob对象包含的文件内容 var oBlob = new Blob([oFileBody], { type: "text/xml"}); oMyForm.append("webmasterfile", oBlob); var oReq = new XMLHttpRequest(); oReq.open("POST", "http://foo.com/submitform.php"); oReq.send(oMyForm);
也可使用JQ的封装的ajax,不过要注意设置processData和contentType属性为false,防止JQ胡乱解析文件格式
var fd = new FormData(document.getElementById("fileinfo")); // 使用某个表单作为初始项 fd.append("CustomField", "This is some extra data"); $.ajax({ url: "stash.php", type: "POST", data: fd, processData: false, // 告诉jQuery不要去处理发送的数据 contentType: false // 告诉jQuery不要去设置Content-Type请求头 });
这里有几个要注意的点:
1)FormData中的属性值接受的是单个文件信息,不能是复合性的对象。可能表意不明,且看
var fd = new FormData($('#form')[0]); fd.append('myFileTest', curFiles); $files = $_REQUEST['myFileTest']; var_dump($files);
用PHP接收传过来的数据,数据却被直接转换成字符串了,非文件对象
curFiles是文件对象,那PHP端是不是应该用$_FILES来接收信息呢,试试换成$files = $_FILES['myFileTest'];
直接出问题了,说明不能这样处理,需要将curFiles内容一项一项拆开,即单个文件信息
var fd = new FormData($('#form')[0]); for (var i = 0, j = curFiles.length; i < j; ++i) { fd.append('myFileTest[]', curFiles[i]); } $files = $_FILES['myFileTest']; var_dump($files);
文件接收成功,接下来就可以按需进行文件的操作了
2)后端获取文件信息的时候,是直接通过原始$_FILES获取的,其他一般的信息才用$_REQUEST获取
换成$files = $_REQUEST['myFileTest'];试试,直接就是出现找不到myFileTest的问题
试试添加一般的文件再提交
var fd = new FormData($('#form')[0]); for (var i = 0, j = curFiles.length; i < j; ++i) { fd.append('myFileTest[]', curFiles[i]); } fd.append('myTest', [1, 2, 3]); $files = $_FILES['myFileTest']; $test = $_REQUEST['myTest']; var_dump($test); var_dump($files);
3)如果需要multiple的多文件上传,则需要在文件项的文件后添加[]号,表示这是一个多文件的数组,以供后端处理解析
fd.append('myFileTest[]', curFiles[i]);
如果没有后面的[],则连续的append会直接覆盖原来的,最后后端获取到的只是最后append进去的项
4)不要直接在JQ的ajax中实例化出一个FormData对象,会出问题
直接在data属性中生成FormData对象,会被JQ忽略,所以后端什么信息也拿不到
混合表单项简单的例子:
在表单处理中,很多时候我们会进行文件上传和其他基础项的提交,简单地多加一个input项目,看看是否处理成功
<input type="number" value="100">
<?php $files = $_FILES['myFileTest']; $test = $_REQUEST['numberTest']; echo json_encode(array( 'len' => count($files['name']), 'num' => $test )); ?>
以下为全部的JS脚本: