在以往的项目,用过三种方式的文件上传,分别是xhr、webuploader、plupload,好记性不如烂笔头,在开始整理笔记的时候,文件上传的优先级就排得敲级高,毕竟特别经常使用嘛~表达能力有限,只能无限开门放代码。。。css
这个方法的兼容性不太好。html
XMLHttpRequest一开始只是微软浏览器提供的一个接口,后来各大浏览器纷纷效仿也提供了这个接口,再后来W3C对它进行了标准化,提出了XMLHttpRequest标准。XMLHttpRequest标准又分为Level 1和Level 2。
XMLHttpRequest Level 1主要存在如下缺点:
受同源策略的限制,不能发送跨域请求;
不能发送二进制文件(如图片、视频、音频等),只能发送纯文本数据;
在发送和获取数据的过程当中,没法实时获取进度信息,只能判断是否完成;jqueryLevel 2对Level 1 进行了改进,XMLHttpRequest Level 2中新增了如下功能:
能够发送跨域请求,在服务端容许的状况下;
支持发送和接收二进制数据;
新增formData对象,支持发送表单数据;
发送和获取数据时,能够获取进度信息;
能够设置请求的超时时间;web
图片是XmlHttpRequest Level 2的兼容性json
从图中能够看到:canvas
IE8/IE九、Opera Mini 彻底不支持xhr对象
IE10/IE11部分支持,不支持 xhr.responseType为json
部分浏览器不支持设置请求超时,即没法使用xhr.timeout
部分浏览器不支持xhr.responseType为blobsegmentfault
以上xhr兼容性描述是引用自https://segmentfault.com/a/11...跨域
如下是我以前写的有进度条的文件上传的demo,里面有css样式,代码比较长。经过给xhr对象添加监听事件,好比beforeSend事件初始化进度条,progress事件返回上传进度等。数组
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name=”renderer” content="webkit|ie-comp|ie-stand"> <meta name="description" content=""> <meta name="keywords" content=""> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>运单上传</title> <style> html, body { width: 100%; height: 100%; padding: 0; margin: 0; overflow: hidden; } body { background: #b4e1f4; position: relative; font-family: '微软雅黑'; } .upload-cont { height: 270px; width: 500px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; background: #f5f1e8; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; -moz-box-shadow: 1px 1px 10px #888888; -webkit-box-shadow: 1px 1px 10px #888888; box-shadow: 1px 1px 10px #888888; } .upload-title { height: 60px; line-height: 60px; color: #fff; font-size: 18px; padding-left: 20px; background: -moz-linear-gradient(top, #ee8f57 0%, #ea7047 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ee8f57), color-stop(100%,#ea7047)); background: -webkit-linear-gradient(top, #ee8f57 0%,#ea7047 100%); background: -o-linear-gradient(top, #ee8f57 0%,#ea7047 100%); background: -ms-linear-gradient(top, #ee8f57 0%,#ea7047 100%); background: linear-gradient(to bottom, #ee8f57 0%,#ea7047 100%); -webkit-border-top-left-radius: 5px; -moz-border-radius-topleft: 5px; border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-topright: 5px; border-top-right-radius: 5px; } .upload-form { padding: 15px 20px; } .upload-hint { color: #48b8e0; } .file-cont { width: 325px; height: 38px; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; border: 1px solid #d3d3d3; vertical-align: middle; margin: 20px 0; padding: 0 10px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .select-btn { position: relative; display: inline-block; vertical-align: middle; margin: 20px 0 20px 5px; } .select-btn input[type=file] { width: 100px; height: 40px; position: relative; z-index: 9; opacity: 0; cursor: pointer; } .select-btn label { position: absolute; display: inline-block; color: #fff; width: 100px; height: 40px; line-height: 40px; text-align: center; top: 0; left: 0; background: #ea7047; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } .cut-line { border-top: 1px solid #d3d3d3; } .progress-bar { height: 22px; width: 345px; margin-top: 18px; display: inline-block; position: relative; border: 1px solid #d3d3d3; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; -moz-box-shadow:1px 1px 8px #888888 inset; -webkit-box-shadow:1px 1px 8px #888888 inset; box-shadow:1px 1px 8px #888888 inset; } .progress-bar-inner { position: absolute; top: 0; left: 0; width: 0%; height: 22px; text-align: center; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; background: -moz-linear-gradient(top, #ee8f57 0%, #ea7047 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ee8f57), color-stop(100%,#ea7047)); background: -webkit-linear-gradient(top, #ee8f57 0%,#ea7047 100%); background: -o-linear-gradient(top, #ee8f57 0%,#ea7047 100%); background: -ms-linear-gradient(top, #ee8f57 0%,#ea7047 100%); background: linear-gradient(to bottom, #ee8f57 0%,#ea7047 100%); } .upload-btn { width: 100px; height: 40px; margin-top: 10px; background: #48b8e0; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; border: none; color: #fff; font-size: 16px; cursor: pointer; float: right; } .mask-bg { position: absolute; top: 0; background: #000; opacity: 0.3; width: 100%; height: 100%; z-index: 1000; } .hint-cont { z-index: 1100; background: #fff; width: 300px; height: 120px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; text-align: center; border-radius: 5px; } .hint-title { display: inline-block; height: 40px; line-height: 40px; } .hint-close { float: right; margin-right: 10px; font-size: 25px; cursor: pointer; } .hint-content { margin-top: 10px; } </style> </head> <body> <div class="upload-cont"> <div class="upload-title">上传文件</div> <form id= "uploadForm" class="upload-form"> <div class="upload-hint">提示:请上传excel文件</div> <div> <input type="text" class="file-cont" disabled> <div class="select-btn"> <input id="fileUpload" type="file" name="file"/> <label>选择文件</label> </div> </div> <hr class="cut-line"> <div id="progressBar" class="progress-bar"> <div class="progress-bar-inner"></div> </div> <input type="button" value="上传" class="upload-btn" onclick="doUpload()" /> </form> <!-----------------------------------> <br> </div> <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script> <script> var resultData; function doUpload(){ var formData = new FormData($( "#uploadForm" )[0]); var xhr = new XMLHttpRequest(); // 上传前初始化 xhr.addEventListener('beforeSend', function () { $('.progress-bar-inner').css('width', '0%').text(''); }); //上传中设置上传的百分比 xhr.upload.addEventListener("progress", function(evt){ if (evt.lengthComputable) { var percentComplete = Math.round(evt.loaded * 100 / evt.total); $('.progress-bar-inner').css('width', percentComplete+"%").text(percentComplete+"%"); }else { $('#progressBar').text('没法计算'); } }, false); //请求完成后执行的操做 xhr.addEventListener("load", function(evt){ var message = evt.target.responseText, obj = eval("("+message+")"); if(obj.status == 1){ showHintDialog(evt); }else{ showHintDialog(obj.message); } }, false); //请求error xhr.addEventListener("error", uploadFailed, false); //请求中断 xhr.addEventListener("abort", uploadCanceled, false); //发送请求 xhr.open("POST", "../excel/in/"); xhr.send(formData); function uploadFailed(evt) { showHintDialog("上传出错"); } function uploadCanceled(evt) { showHintDialog("上传已由用户或浏览器取消删除链接"); } } function showHintDialog (str) { var urlHtml; if (typeof str == 'object') { if(!str.success) { if (str.errorMessage.startsWith('http')) { urlHtml = '<a href=" ' + str.errorMessage + '"onclick="closeHint()" target="_blank" style="color:red">有错误运单数据,请点击下载</a>'; } else { urlHtml = '<p style="color: red">' + str.errorMessage + '</p>'; } }else{ urlHtml = '<p style="color: black">文件上传成功 </p>'; } } var dialogHtml = '<div id="alertStrCont"><div class="mask-bg" onclick="closeHint()"></div><div class="hint-cont"><span class="hint-title">提示</span><span class="hint-close" onclick="closeHint()">×</span><div class="hint-content">'+urlHtml+'</div></div></div>'; $('body').append(dialogHtml); } function closeHint() { $('#alertStrCont').remove(); } $('#fileUpload').on('change', function () { if (this.files.length === 0) { return; } var oFile = this.files[0]; $('.file-cont').val(oFile.name); }) </script> </body> </html>
补充:有用xhr作过图片直传七牛。用canvas压缩了图片,该方法仍是不兼容IE8,是用appcan作一个小项目的时候用过。附上代码。(需求是多图片上传,须要一张一张上传,而且若是有其中一张图片在上传时失败,则中止上传剩下的图片,若是所有上传成功,则提交整个表单,submitDone()方法就是提交表单,由于与本文没什么关系,就不写出来了。)浏览器
function putb64(dataArr) { var pic = dataArr[isSuc].substring(23); // pic是图片的base64编码 var timestamp = (new Date()).valueOf(); var url = "http://upload.qiniu.com/putb64/-1"; var xhr = new XMLHttpRequest(); xhr.open("POST", url, true); xhr.setRequestHeader("Content-Type", "application/octet-stream"); xhr.setRequestHeader("Authorization", "UpToken " + $("input[name=token]").val()); xhr.send(pic); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) { var data = $.parseJSON(xhr.responseText); key.push(data.key); ++isSuc; if (isSuc < baseArr.length) { putb64(dataArr); } else if (isSuc == baseArr.length) { submitDone(); } } else { appcan.window.alert({ title : '', content : xhr.responseText, buttons : '肯定' }); stopLoading(); toast('图片上传失败'); } } } }
附上图片转base64编码方法
var img = new Image(); img.src = imgArr[imgIndex]; //imgArr是图片数组 img.onload = function() { var canvas = document.createElement("canvas"); canvas.width = img.width; canvas.height = img.height; var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0); var dataURL = canvas.toDataURL("image/jpeg", 0.4); // 0.4就是图片压缩的程度 baseArr.push(dataURL); }