跳至主要內容
Skip to content

檔案上傳系統設計 (6) —— 前端上傳的專業修養

在前面的篇幅中,我們把後端的「內功」練好了。現在,我們要回到使用者最直接接觸的地方:瀏覽器前端

一個專業的檔案上傳功能,絕不是放個按鈕、選完檔案就轉圈圈等待而已。使用者需要知道「傳了多少」、需要有「後悔取消」的權利,甚至希望不用打開資料夾,直接從桌面「拖進來」或「貼進來」就能完成。


一、 進度監控:讓使用者等得心安

當檔案超過 2MB 時,如果沒有進度條,使用者會陷入「這是有在傳,還是卡住了?」的焦慮。

1. 傳統但強大的 XMLHttpRequest (XHR)

雖然現在流行 fetch,但在監控 上傳 (Upload) 進度方面,XHR 仍然是最直覺的選擇。

javascript
const xhr = new XMLHttpRequest();
const formData = new FormData();
formData.append("file", file);

xhr.upload.onprogress = (event) => {
  if (event.lengthComputable) {
    const percent = Math.round((event.loaded / event.total) * 100);
    console.log(`上傳進度:${percent}%`);
    // 更新 UI 進度條
  }
};

xhr.open("POST", "/upload");
xhr.send(formData);

2. 為何 Fetch 比較難監控「上傳」進度?

現代的 fetch API 原生支援監控 下載 進度(透過 ReadableStream),但對於 上傳 進度的支持目前在各瀏覽器中仍不夠純熟。這也是為什麼許多專業上傳套件(如 axiosUppy)在底層仍會選用 XHR。


二、 撤回權:如何取消正在進行的上傳?

假設使用者點錯了檔案,或突然網路變慢不想傳了,你的 UI 必須提供一個「取消」按鈕。

使用 AbortController

這是現代 Javascript 的標準作法,可以用來中斷任何 fetch 請求。

javascript
const controller = new AbortController();
const signal = controller.signal;

fetch("/upload", {
  method: "POST",
  body: formData,
  signal: signal, // 綁定信號
}).catch((err) => {
  if (err.name === "AbortError") {
    console.log("上傳已被使用者取消");
  }
});

// 當點擊取消按鈕時執行:
// controller.abort();

三、 進階交互:拖放與貼上 (Drag, Drop & Paste)

專業的產品(如 GitHub, Slack)都支持這兩種操作:

1. 拖放 (Drag & Drop)

使用者不需要點擊 Input,直接將檔案拖入特定目標區域。

javascript
const dropZone = document.getElementById("drop-zone");

dropZone.ondragover = (e) => e.preventDefault(); // 必須阻擋預設行為

dropZone.ondrop = (e) => {
  e.preventDefault();
  const files = e.dataTransfer.files; // 這裡拿到檔案列表
  handleUpload(files[0]);
};

2. 剪貼簿貼上 (Paste)

當你截圖後(或在資料夾複製檔案),直接在網頁 Ctrl+V (或 Cmd+V)。這對聊天室或 Markdown 編輯器極其好用。

javascript
document.addEventListener("paste", (e) => {
  const items = e.clipboardData.items;
  for (let item of items) {
    if (item.kind === "file") {
      const file = item.getAsFile();
      handleUpload(file);
    }
  }
});

總結

前端的專業度體現在「掌控感」與「便捷度」:

  1. 進度條:利用 xhr.upload 即時回報,消弭等待焦慮。
  2. 取消機制:使用 AbortController 賦予使用者反悔的權力。
  3. 多元輸入:透過 Drag & DropPaste 大幅提升操作效率。

下一篇,我們將聊聊如何透過「客戶端預處理」進一步減少伺服器壓力。


️ 進階挑戰

在顯示進度條時,為什麼我們通常不建議直接顯示到 100%?當進度條跑到 100% 但後端還沒回傳 Response 時,你會如何優化 UI 提示?


延伸閱讀與資源

← 上一章:邁向雲端架構 | 返回專案首頁 | 下一章:客戶端預處理的威力