1. 程式人生 > 前端設計 >FormData上傳檔案到伺服器

FormData上傳檔案到伺服器

後端配置

上傳檔案一定是 post 請求,這裡我們使用 koa 實現一個簡易的 post 請求,並且讓獲取前端發來的 formdata 資料 並進行一些簡易的處理 ;

const Koa = require('koa');
const Router = require('koa-router');
const koaBody = require('koa-body');

let app = new Koa();
let router = new Router();

app.use(koaBody({
  multipart: true // 允許客戶端上傳檔案
}));

router.post('/upload'
,async (ctx,next) => { // 客戶端上傳的檔案會在這個物件中存在 ctx.request.files // 讀取這個檔案,然後存到 upload 資料夾,實現簡易的儲存檔案功能 let data = fs.readFileSync(ctx.request.files.image.path); fs.writeFileSync(path.join(__dirname,'upload',ctx.request.files.image.name),data); ctx.body = { status: 1 }; }); app.use(router.routes()); app.listen(3000
);
複製程式碼

前端實現單檔案上傳

前端這裡使用 FormData 物件和 XMLHttpRequest 物件來實現檔案上傳

這裡咱們就先不考慮樣式了,只是簡單實現功能

<input type="file" />
<button>點選上傳</button>
複製程式碼
document.querySelector('button').onclick = function () {
  // 這裡會獲取一個 files 陣列物件 因為是單檔案上傳取第一個即可
  let file = document.querySelector('input').files[0];
  let
xhr = new XMLHttpRequest(); xhr.open('post','/upload',true); xhr.onload = function () { let res = JSON.parse(xhr.responseText); console.log(res); } let form = new FormData(); form.append('image',file); // 對應 key value xhr.send(form); }
複製程式碼

到這裡,就已經實現了 檔案上傳並且通過服務端進行轉存 ; 需求怎麼可能這麼簡單就實現呢,我們可以再新增一些拓展,比如進度條,和上傳速度 ;

單檔案的上傳速度與進度條

html 優化部分 : 這裡進度條,我們就根據 html5 原生的 progress 標籤來實現 ;

<input type="file" />
<progress value="0" max="100"></progress>
<span class="percent">0 %</span>
<span class="speed">0 b/s</span>
<button>點選上傳</button>
複製程式碼

js 鋪墊 ; 這裡如果想要知道上傳的進度和當前下載的速度,我們肯定要辦到下面一些事情 ;

  • 上傳檔案時的狀態監控

xhr.upload 下面有檔案上傳時的鉤子,我們可以利用這些鉤子函式實現進度條的監控

https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/upload

  • 獲取檔案的大小 total
  • 獲取當前下載的大小 size

可以通過 鉤子函式中的 event 獲取到 total 和 size https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequestEventTarget/onprogress

let startTime;
let startSize;
document.querySelector('button').onclick = function () {
  // 這裡會獲取一個 files 陣列物件 因為是單檔案上傳取第一個即可
  let file = document.querySelector('input').files[0];
  let xhr = new XMLHttpRequest();
  xhr.open('post',file); // 對應 key value
  
  xhr.upload.onloadstart = function () {
    // 開始上傳鉤子
    startTime = new Date().getTime();
    startSize = 0;
  }
  xhr.upload.onprogress = function (event) {
   // 正在上傳鉤子,會被多次呼叫
   // 已傳輸的資料量 / 總共的資料量 * 100
   let percent = (event.loaded / event.total * 100).toFixed(0);
   document.querySelector('progress').value = percent;
   document.querySelector('.percent').innerHTML = percent + ' %';
   
   let currentTime = new Date().getTime();
   let dtime = (currentTime - startTime) / 1000; // 時間差 s
   startTime = new Date().getTime(); // 計算完成後重新獲取時間
   
   let dsize = event.loaded - startSize; // 大小差 b
   startSize = event.loaded; // 計算完成後重新獲取帶下
   
   let speed = dsize / dtime; // 速度
   let unit = 'b/s';  // 單位
   // 單位進位制計算
   if (speed / 1024 > 1) {
     speed = speed / 1024;
     unit = 'kb/s';
   }
   if (speed / 1024 > 1) {
     speed = speed / 1024;
     unit = 'mb/s';
   }
   
   document.querySelector('.speed').innerHTML = speed.toFixed(2) + unit;
  }
  // 上傳完成後重置 進度條等
  xhr.onload = function () {
   document.querySelector('progress').value = 0;
   document.querySelector('.percent').innerHTML = 0 + ' %';
   document.querySelector('.speed').innerHTML = '0b/s';
  }
  xhr.send(form);
}
複製程式碼

axios 單檔案上傳帶進度條

axios 中監控進度,通過 onUploadProgress 鉤子來監控進度

axios.post('/upload',form,{
  onUploadProgress: event => {
    let complete = (event.loaded / event.total * 100 | 0)
    document.querySelector('progress').value = complete;
    document.querySelector('.percent').innerHTML = complete + ' %';
    if (complete >= 100) {
      document.querySelector('progress').value = '0';
      document.querySelector('.percent').innerHTML = 0 + ' %';
    }
  },}).then(res => {
  console.log(res)
});
複製程式碼

效果展示

GIF

本文使用 mdnice 排版