在以往的項目,用過三種方式的文件上傳,分別是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); }