檔案上傳五種方法對比
阿新 • • 發佈:2019-01-12
檔案上傳
這裡參考阮一峰老師的部落格,原文寫於2012年,現在需要不斷學習新東西。
早期不同檔案上傳瀏覽器相容性不好。現在HTML5出現後有了統一的介面。
1、早期 form 表單同步上傳
<form id="upload-form" action="upload.php" method="post" enctype="multipart/form-data" >
<input type="file" id="upload" name="upload" /><br />
<input type="submit" value="Upload" />
</form>
這樣介面不是很好,需要後端程式碼php進行接收。
早期的 form 上傳是同步上傳,點選上傳後介面鎖死,等待上傳結束後,瀏覽器重新整理到新的介面。
2、iframe 非同步上傳
點選提交按鈕後,介面中插入 iframe
var form = $("#upload-form");
form.on('submit',function() {
// 此處動態插入iframe元素
var seed = Math.floor(Math.random() * 1000);
var id = "uploader-frame-" + seed;
var callback = "uploader-cb-" + seed;
var iframe = $('<iframe id="'+id+'" name="'+id+'" style="display:none;">');
var url = form.attr('action');
form.attr('target', id).append(iframe).attr('action', url + '?iframe=' + callback);
});
最後一行,有兩個地方值得注意。首先,它為表單新增target屬性,指向動態插入的iframe視窗,這使得上傳結束後,伺服器將結果返回iframe視窗,所以當前頁面就不會跳轉了。其次,它在action屬性指定的上傳網址的後面,添加了一個引數,使得伺服器知道回撥函式的名稱。這樣就能將伺服器返回的資訊,從iframe視窗傳到上層頁面。
介面返回程式碼(php)這種情況可以處理不支援 H5 的舊瀏覽器
<script type="text/javascript">
window.top.window['callback'](data);
window[callback] = function(data){
console.log('received callback:', data);
iframe.remove();
//removing iframe
form.removeAttr('target');
form.attr('action', url);
window[callback] = undefined;
//removing callback
};
</script>
3、Ajax 非同步上傳
使用 form-data 進行檔案上傳
// 檢查是否支援FormData
if(window.FormData) {
var formData = new FormData();
// 建立一個upload表單項,值為上傳的檔案
formData.append('upload', document.getElementById('upload').files[0]);
var xhr = new XMLHttpRequest();
xhr.open('POST', $(this).attr('action'));
// 定義上傳完成後的回撥函式
xhr.onload = function () {
if (xhr.status === 200) {
console.log('上傳成功');
} else {
console.log('出錯了');
}
};
xhr.send(formData);
}
現在用這個方法測試檔案上傳
關鍵問題:這個請求是ajax請求,需要非同步上傳,所以在請求頭需要設定,表示 ajax 請求。
form.getHeaders = function() {
return {'X-Requested-With': 'XMLHttpRequest'};
}
不同的後端需要加入不同的字首。例如專案的後端對於ajax 請求,在請求頭中必須加入對應的說明。
4、Progress 進度條上傳
<progress id="uploadprogress" min="0" max="100" value="0">0</progress>
xhr.upload.onprogress = function(e) {
if (e.lengthCompatable) {
let complate = (e.loaded / e.total * 100 | 0);
let progress = document.getElementById('uploadprogress');
progress.value = progress.innerHTML = complete;
}
};
//注意 需要繫結的是 xhr.upload 的 onprogress 事件,不是 xhr 的事件
5、圖片上傳預覽
// 檢查是否支援FileReader物件
if (typeof FileReader != 'undefined') {
var acceptedTypes = {
'image/png': true,
'image/jpeg': true,
'image/gif': true
};
if (acceptedTypes[document.getElementById('upload').files[0].type] === true) {
var reader = new FileReader();
reader.onload = function (event) {
var image = new Image();
image.src = event.target.result;
image.width = 100;
document.body.appendChild(image);
};
reader.readAsDataURL(document.getElementById('upload').files[0]);
}
}
6、拖拽上傳
// 檢查瀏覽器是否支援拖放上傳。
if('draggable' in document.createElement('span')){
var holder = document.getElementById('holder');
holder.ondragover = function () {
this.className = 'hover';
return false;
};
holder.ondragend = function () {
this.className = '';
return false;
};
holder.ondrop = function (event) {
event.preventDefault();
this.className = '';
var files = event.dataTransfer.files;
// do something with files
};
}
<div id="holder"></div>
#holder {
border: 10px dashed #ccc;
width: 300px;
min-height: 300px;
margin: 20px auto;
}
#holder.hover {
border: 10px dashed #0c0;
}