趁早填坑。
簡述
在實際介紹下載檔案的方法前,我覺得先認識底下幾個東西會比較好上手:
<input type="file">
的使用方式window.URL.createObjectURL
的用法Blob
資料格式和轉換格式的觀念
看完後你就會覺得下載檔案並沒有想像中那麼困難囉。
先從 HTML 標籤開始
要讓使用者上傳檔案的話基本上都會透過 <input type="file">
來實作,他的基本用法是像這樣:
1 | <input type="file" multiple accept="image/*" /> |
1 | document.querySelector('input').addEventListener('change', function () { |
輸出結果:
懶人包:
- input 可以用來讓使用者上傳檔案,依據需求可以添加
multiple
來決定使否能多選?accept
決定只能選擇哪些 MIME 類型的檔案 - input 節點會有
files
這個屬性,就是 File 物件(儲存檔案的資訊)
createObjectURL
他是一個 HTML5 的 API,我們先來看它在文件上的定義:
Object URL is a URL representing a object. The URL lifetime is tied to the document in the window on which it was created. The new object URL represents the specified File object or Blob object. — MDN
簡單來說他是用來「建立 URL 的一個物件」,但這個物件的值必須是「File」或是「Blob」。
File 可以透過 <input type="file">
上的 files
屬性來取得,而 Blob 則是一種資料格式。如果目前不太懂這兩個東西也沒關係,後面會再解釋,只要先記得下面這個原則就好:
- 輸入:File / Blob
- 輸出:URL
重點在於輸出URL,因為是 URL 的關係,所以只要是任何使用 URL 的標籤都可以拿來用,像是 <img>
和 <a>
(通常是拿來做下載功能)。
這邊有一個很經典的例子:如果我想實作預覽圖片的功能怎麼做?這很常出現在「換頭像」的時候。
順道一提這種作法是有好處的,可以參考這篇:HTML5 神奇的 Object URL:不用後端,前端便能產生獲取指定物件的網址
只要透過 createObjectURL
可以很輕鬆的做到這件事:
1 | <div class="container mt-5"> |
1 | document.querySelector('input').addEventListener('change', function () { |
實際範例可以參考這裡。
關於 Blob 與 File
Blob 其實就是一種「資料格式」,Blob 是縮寫,全名為「Binary Large Object(二進位大型物件)」,而 File 是基於 Blob 來製作的另一種資料格式,所以本質上是差不多的東西。
這就跟 JSON 是一樣的道理,兩個都只是用來表示資料的一種「格式」,不用想得太複雜。
不過我們都知道碰到 JSON 時我們要用 JSON.parse
來解析,那 Blob 呢?
這邊要先說一個重要觀念:
JS 本身就是只能操作 JavaScript,而 Blob 沒辦法像 JSON 一樣可以轉換成 JavaScript,所以你是沒辦法直接用 JS 來操作 Blob 的。
你唯一能做的就是透過 Blob 來產生一段 url,接著再綁到對應的 HTML 標籤上來做處理(下載 or 顯示內容),畢竟 blob 的用途主要就是拿來處理檔案。
所以這邊先講步驟,待會再來示範:
- 建立 Blob 物件
- 透過
createObjectURL
來建立一個屬於 blob 的 URL - 把 URL 綁到相關的 HTML 標籤上
這邊我要示範的是把一份 JSON 資料轉成 Blob,接著再把這個 Blob 轉成連結來打開它:
1 | const jsonData = JSON.stringify({ hello: 'blob' }, null, 2) |
附註:實際示範可以參考這邊
補充一下 new Blob
的部分:
簡單來說他會接收兩個參數,第一個是「你要轉換的資料(必須放在陣列裡)」,第二個則是「MIME Type(簡單來說就是檔案類型啦)」,所以 new Blob([jsonData], { type: 'application/json' })
的意思就是:
[jsonData]
= 要轉換的資料{ type: 'application/json' }
= MIME type
至於詳細的 MIME 列表可以參考 MDN
實作下載檔案
其實主要的概念就是前面說的 new Blob
和 createObjectURL
,所以這邊就直接附上 code:
(這邊是透過 API 來取得對應的 Excel 檔案)
1 | api |
這段的背後其實只是把 blob 產生的網址拿來寫入這段 HTML 後再幫你自動點擊:
1 | <a |
附註:當 <a>
有 dowload
屬性時就等於下載檔案
所以下載檔案的實作還蠻單純的,只要搞清楚資料格式怎麼轉換就好了。順道一提,如果檔案是透過 AJAX 來取得的話,請務必:
- 在 header 加上
responseType = 'blob'
- 在 header 加上
responseType = 'blob'
- 在 header 加上
responseType = 'blob'
這樣子才會把 response 轉成 blob 的形式。看很多人都被這個雷到,所以特別強調一下。