最近做一个项目用到图片上传,用的是blueimp大神的jQuery-File-Upload插件,用完瞬间想研究一下图片上传原理,而且发现一个问题:多图上传时会多次发送请求~
一、图片上传原理
XMLHttpRequest Level 2 添加了一个新的接口 FormData,利用 FormData 对象,我们可以通过 JavaScript 用一些键值对来模拟一系列表单控件,我们还可以使用 XMLHttpRequest 的 send() 方法来异步的提交表单。与普通的 Ajax 相比,使用 FormData 的最大优点就是我们可以异步上传二进制文件。
FormData实例代码:
//ajax+FormData上传 function uploadByAjax(element){ var formData = new FormData(),//创建formData对象 fileArr = element.files, //读取文件域的文件 fileIptName = element.name; //获取name名 //循环将文件域的文件存入formData if(fileIptName && fileArr.length){ for(var i = 0; i < fileArr.length; i++){ formData.append(fileIptName,fileArr[i]); } } $.ajax({ url: settings.url, type: "post", data: formData, dataType: 'json', cache: false, contentType: false, //必须false才会自动加上正确的Content-Type processData: false //必须false才会避开jQuery对 formdata 的默认处理 }).done(function(data){ settings.uploadSuccess(element,data); }).fail(function(){ settings.uploadFail(data); }) }
具体的FormData用法可以访问MDN关于FormData的用法
哇,好像看起来很美好,But!!! 这是HTML5新属性而且IE10以下版本是不兼容的。
别担心!有其他的解决方案,那就是利用iframe提交。
ifame提交原理:动态创建ifame元素和form元素,插入到DOM中,把上传的input插入到form内,form的target指向iframe的name,form的action则是上传地址,上传完时刷新的是iframe,父页不会刷新,所以感觉像是无刷新上传。上传完毕后,后端会将把返回数据输出到ifame页面中,前端再读取iframe中的内容即可。
ifame实例代码:
//iframe模拟上传 function uploadByIframe(element){ var iframe = '<iframe src="javascript:false;" name="my_upload_form_target" style="display:none;width:0;height:0;"></iframe>'; form = '<form action="'+defaults.url+'" method="post" enctype="multipart/form-data" target="my_upload_form_target" style="display:none;width:0;height:0;"></form>', $iframe = $(iframe).appendTo(document.body), $form = $(form).appendTo(document.body), $file = $(element).appendTo($form); $form.on('submit',function(){ $iframe.on('load',function(){ var data = $iframe.contents().find('body').text(); var json = eval('json='+data); settings.uploadSuccess(element,json); $iframe.remove(); $form.remove(); }); }); //触发表单提交事件 $form.trigger('submit'); }
二、后端实现
<?php /* * [fileFileUpload 图片上传] * @data: 2016-12-09 * @author: yuuk */ class upload { public function upload(){ //如果有上传文件 if($_FILES || $_POST){ // 上传的路径,建议写物理路径 $uploadDir = 'upload'; // 文件数组 $totalFile = array('status'=>1,'files'=>array()); //formData上传 if($_FILES['pic']){ $fileCount = count($_FILES['pic']['name']); } //post上传 else{ $fileCount = count($_POST['pic']['name']); } //判断文件是否存在 if($fileCount){ for ($i = 0; $i < $fileCount; $i++) { //formData上传 if($_FILES['pic']){ $tempFiles = $_FILES['pic']['tmp_name'][$i]; //临时文件 $files = $_FILES['pic']['name'][$i]; //真实文件 } //post上传 else{ $tempFiles = $_POST['pic']['tmp_name'][$i]; //临时文件 $files = $_POST['pic']['name'][$i]; //真实文件 } // 如果不存在文件夹则创建文件夹 if(!file_exists($uploadDir)){ mkdir($uploadDir, 0777); } // 用时间戳来保存图片,防止重复 $targetFile = $uploadDir . '/' . time() . '_' . $files; // 将临时文件 移动到我们指定的路径 move_uploaded_file($tempFiles, $targetFile); // 将文件地址返放入数组 array_push($totalFile['files'],$targetFile); } } return json_encode($totalFile);; exit; } else{ die('Unable to connect'); exit; } } } $uploader = new upload(); echo $uploader->upload(); ?>
三、完整实例
移步至github项目地址:jQuery-ajaxFileUpload