檔案上傳進度提示

雲棲直播~發表於2018-07-09

需求

當上傳的檔案相對較大時,使用者可能需要等待較長的時間,這個時候前端如果沒有任何提示的話,體驗不是很好,如果有上傳進度提示,就會好很多。而要在上傳過程實時顯示上傳進度,則需要已上傳的大小和檔案總大小。

前提

  • 請求是非同步的。因為要實時獲取到上傳的進度,則請求需是非同步的,如果是同步的話,會直到請求完成才能獲取到響應。

實現

這裡總結的主要是js方面,至於進度條的顯示,有的UI框架,比如semantic就自帶了進度條的實現,直接使用即可,沒有的話也可以自己用改變div寬度等方式實現,這裡不贅述。

如何獲取到檔案的上傳進度?
Javascript的XMLHttpRequest提供了一個progress事件,這個事件會返回檔案已上傳的大小和總大小,根據這兩個值,就可以計算上傳進度了,關於這個方法,在《Javascript高階程式設計(第3版)》21章第3節中有敘述,有這本書在手的可以看一下。下面貼一下程式碼。

XMLHttpRequest:progress事件

使用Javascript的XMLHttpRequest的progress事件,實現示例程式碼為:

var formData = new FormData(); 
formData.append("file", document.getElementById(`file`).files[0]); 
formData.append("token", token_value); // 其他引數按這樣子加入

var xhr = new XMLHttpRequest();
xhr.open(`POST`, `/uploadurl`);
// 上傳完成後的回撥函式
xhr.onload = function () {
  if (xhr.status === 200) {
  console.log(`上傳成功`);
  } else {
   console.log(`上傳出錯`);
  }
};
// 獲取上傳進度
xhr.upload.onprogress = function (event) {
  if (event.lengthComputable) {
    var percent = Math.floor(event.loaded / event.total * 100) ;
    // 設定進度顯示
    $("#J_upload_progress").progress(`set progress`, percent);
  }
};
xhr.send(formData);
複製程式碼

關於FormData和XMLHttpRequest, 可以搜下W3C瞭解詳情。

jQuery封裝的xhr

jQuery封裝了xhr的實現, 也可以使用jQueryajax獲得上傳進度,示例程式碼:

var formData = new FormData(); 
formData.append("file", document.getElementById(`file`).files[0]); 
formData.append("token", token_value); 

$.ajax({ 
    url: "/uploadurl", 
    type: "POST", 
    data: formData, 
    processData: false, // 不要對data引數進行序列化處理,預設為true
    contentType: false, // 不要設定Content-Type請求頭,因為檔案資料是以 multipart/form-data 來編碼
    xhr: function(){
        myXhr = $.ajaxSettings.xhr();
        if(myXhr.upload){
          myXhr.upload.addEventListener(`progress`,function(e) {
            if (e.lengthComputable) {
              var percent = Math.floor(e.loaded/e.total*100);
              if(percent <= 100) {
                $("#J_progress_bar").progress(`set progress`, percent);
                $("#J_progress_label").html(`已上傳:`+percent+`%`);
              }
              if(percent >= 100) {
                $("#J_progress_label").html(`檔案上傳完畢,請等待...`);
                $("#J_progress_label").addClass(`success`);
              }
            }
          }, false);
        }
        return myXhr;
    },
    success: function(res){ 
        // 請求成功
    },
    error: function(res) {
        // 請求失敗
        console.log(res);
    }
}); 
 複製程式碼

關於jQuery ajax的xhr, 具體可檢視W3C。

vue-resource

var formData = new FormData();
formData.append(`token`, token_value);  // csrf token
formData.append("works", document.getElementById(`file`).files[0]); // file
var url = $("#R_batch_upload_url").val();

vm.$http.post(url, formData, {
  progress: (e) => {
    if (e.lengthComputable) {
      var percent = Math.floor(e.loaded/e.total*100);
      if(percent <= 100) {
        $("#J_progress_bar").progress(`set progress`, percent);
        $("#J_progress_label").html(`已上傳:`+percent+`%`);
      }
      if(percent >= 100) {
        $("#J_progress_label").html(`檔案上傳完畢,提交表單中,請等待...`);
        $("#J_progress_label").addClass(`success`);
      }
    }
  }
})
.then((res) => {
  if(res.ok && res.status === 200) {
    window.location.href = window.location.href;
  }
}, (res) => {
  if(res.status === 400) {
      $("#J_progress_label").html(`檔案格式錯誤,請修改後重試`);
      $("#J_progress_label").addClass(`warning`);
      console.log(res);
      vm.errMsg.show = true;
      vm.errMsg.msg = res.body.msg;
      vm.canSend = true;
      // TODO hide the loader dimmer
      $("#J_upload_batch").dimmer("hide");
    } else {
      $("#J_progress_label").html(res.statusText);
      $("#J_progress_label").addClass(`warning`);
    }
});複製程式碼

七牛雲儲存

有些檔案過大,後臺會採取上傳到七牛,再獲取其地址儲存到資料庫的方式,這種方式的話,前端可以使用上面兩種方式XMLHttpRequest或jQuery封裝的xhr實現傳送請求及獲取上傳進度,如果需要更復雜的上傳資料處理,也可以考慮使用七牛提供的配套Javascript SDK實現,若是隻需要進度提示的話,並不需要引入七牛JS SDK。

另外一點,上傳成功後設定重定向到網站某頁面的話,可能會報錯跨域重定向。

相關連結




原文釋出時間為:2018年07月02日

作者:掘金

本文來源:掘金 如需轉載請聯絡原作者


相關文章