1. 程式人生 > >檔案上傳五種方法對比

檔案上傳五種方法對比

檔案上傳

這裡參考阮一峰老師的部落格,原文寫於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;
  }