0%

JS 筆記 - 透過 JavaScript 生成一個檔案並下載

download

看到上方這張圖片,如果喜歡的話會怎麼儲存呢?

沒錯~就是在圖片上點選右鍵並且選擇「另存圖片」下載它,那該怎麼做?

在 a 連結中即可實現

W3School 的範例程式碼:

1
<a href="/images/myw3schoolsimage.jpg" download></a>

只要在 image 資料中的檔案,透過 a 連結,最後加上 download 屬性就可以完成這個功能。

但是今天 PM 跑來說:
「客戶那邊要求在表單下方要有一個按鈕,表單所產生的 data 的資料,按下按鈕可以下載,然後這個檔案要用 excel 打開。」

所以獲得以下資訊:

  1. 有一個按鈕。
  2. 會有 data 資料產生。
  3. 有下載功能。
  4. 要用 excel 可以打開的格式。

這時馬上請教 Google 大神,然後找到了 Blob,跟想起來好像 excel 匯出有一個叫做 CSV 格式檔案,會用來匯入的。

CSV 逗號分隔值

逗號分隔值(Comma-Separated Values,CSV,有時也稱為字元分隔值,因為分隔字元也可以不是逗號),其檔案以純文字形式儲存表格資料(數字和文字),更多請看維基百科

Blob

MDN 這樣解釋:
Blob(Binary Large Object)物件代表了一個相當於檔案(原始資料)的不可變物件。Blob 中的資料並不一定是 JavaScript 原生的格式。File 介面基於 Blob,繼承 blob 並擴充其功能以支援操作使用者系統上的檔案。

看一下程式碼:

HTML

1
<button class="downloadBtn">Download File</button>

JavaScript

綁定 button 與建立監聽事件 click,

1
2
let downloadBtn = document.querySelector(".downloadBtn");
downloadBtn.addEventListener("click", downloadFile);

在函式 downloadFile(); 寫入要下載的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function downloadFile() {
//藉型別陣列建構的 blob 來建立 URL
let fileName = "fileName.csv";
const data = getRandomData();
let blob = new Blob([data], {
type: "application/octet-stream"[註1],
});
var href = URL.createObjectURL(blob);
// 從 Blob 取出資料
var link = document.createElement("a");
document.body.appendChild(link);
link.href = href;
link.download = fileName;
link.click();
}
  1. 先命名一個變數等於下載的檔案名稱。

  2. data 用一個 function 取得。

  3. new Blob 的方法參考 MDN 介紹的 Blob。

    var blob = new Blob([typedArray], {type: ‘application/octet-binary’}); // pass a useful mime type here
    var url = URL.createObjectURL(blob);

  4. 接下來命名一個變數,讓其在網頁建立一個 a 連結功能。

  5. 在網頁文件的 body 瀏覽器新增一個子節點,其參數為剛剛建立的 a 連結。

  6. a 連結的屬性等於剛剛宣告的 href 變數。

  7. 再給 a 連結一個 download 點擊事件等於宣告的文件檔案名稱。

  8. 產生點擊事件。

補充:
外部建立 click 的監聽事件,是呼叫 function 用,而 function 內的 click();,是針對透過 JS 建立的 a 連結所產生的點擊事件,所以兩個是不同的!

假資料

1
2
3
4
5
6
7
8
9
10
11
12
13
function getRandomData() {
var header = "RandomHeader";
var data = "";
for (let i = 0; i < 5; i++) {
for (var j = 0; j < 2; j++) {
if (j > 0) {
data = data + ",";
}
data = data + "Item" + i + "_" + j;
}
}
return header + data;
}

codepen: https://codepen.io/hnzxewqw/pen/WNQKMKG

用 JS 寫一個載入檔案 load File 功能

有下載檔案,一定也有透過本地端載入檔案到網頁上的功能,在 HTML 5 有建立一個 load 的語法,但會有預設的樣式,

1
<input type="file" id="myfile" name="myfile" />

Codepen https://codepen.io/hnzxewqw/pen/dyYQzOy

但這次專案中是使用 button 按鈕來取得檔案,要有美美的按鈕,所以改寫一下,

1
2
<input type="file" id="file" hidden />
<button class="btn_loadFile">Load File</button>

因為在 input 使用 hidden 屬性,所以原本預設的 input 就會看不見。必須使用 JS 來控制該功能,這邊使用的是 jQuery,

1
2
3
$(".btn_loadFile").click(function () {
$(":file").trigger("click");
});

這樣就可以實現檔案下載的功能,又能具備好看的 button。

CodePen https://codepen.io/hnzxewqw/pen/zYvMdoy

註 1.
網際網路媒體類型(Internet media type,也稱為 MIME 類型(MIME type)或內容類型(content type))是給網際網路上傳輸的內容賦予的分類類型。這邊的情境是
application/octet-stream:任意的二進制檔案(通常做為通知瀏覽器下載檔案),還有很多種類型的介紹,請見維基百科。