前端js實現字串/圖片/excel檔案下載
在web
開發中,如果你想讓使用者下載或者匯出一個檔案,應該怎麼做呢?
傳統的做法是在後端儲存或者即時生成一個檔案來提供下載功能,這樣的優勢是可以做許可權控制、資料二次處理,但缺點是需要額外發起請求、增大服務端壓力、下載速度慢。
但隨著HTML5
的標準釋出,我們已經能夠做到只前端來下載各種檔案了。
<a>
標籤的download
屬性
此屬性指示瀏覽器下載URL
而不是導航到它,因此將提示使用者將其儲存為本地檔案。如果屬性有一個值,那麼它將作為下載的檔名使用。此屬性對允許的值沒有限制,但是/
和\
會被轉換為下劃線。
-
此屬性僅適用於同源
URLs
。 -
儘管
HTTP URL
需要位於同一源中,但是可以使用blob: URLs
和data: URLs
,以方便使用者下載JavaScript
方式生成的內容(例如使用線上繪圖的Web
應用建立的照片)。
常規的<a>
標籤,用於連結的跳轉,如新的頁面,那麼如果我們給<a>
標籤加上download
屬性,就能很簡單的讓使用者儲存新的html
頁面。
<a download="PHP實現併發請求.html" href="https://segmentfault.com/a/1190000016343861">PHP實現併發請求</a>
生成並下載字串檔案
首先我們需要了解一個特殊的資料格式:Blob
。
Blob
資料
Blob(Binary Large Object,二進位制型別的大物件)
,表示一個不可變的原始資料的類檔案物件,我們上傳檔案時常用的File
物件就繼承於Blob
,並進行了擴充套件用於支援使用者系統上的檔案。
我們只能通過Blob()
建構函式來建立一個新的Blob
物件:
Blob(blobParts[, options])
// 建立一個json型別的Blob物件,支援傳入同類型資料的一個數組 var debug = {hello: "world"}; var blob = new Blob([JSON.stringify(debug, null, 2)], {type : 'application/json'}); // 此時blob的值 // Blob(22) {size: 22, type: 'application/json'}
Blob
物件存在兩個只讀屬性:
size
: Blob 物件中所包含資料的大小(位元組)。
type
: 一個字串,表明該Blob物件所包含資料的MIME型別。如果型別未知,則該值為空字串。
URL
物件和下載字串檔案
URL
介面是一個用來建立URLs
的物件,包含兩個靜態方法:
objectURL = URL.createObjectURL(blob)
建立一個
URL(DOMString)
,包含一個唯一的blob連結(該連結協議為以blob:,後跟唯一標識瀏覽器中的物件的掩碼)。這個 URL 的生命週期和建立它的視窗中的 document 繫結。
URL.revokeObjectURL(objectURL)
銷燬之前使用URL.createObjectURL()方法建立的URL例項。瀏覽器會在文件退出的時候自動釋放它們,但是為了獲得最佳效能和記憶體使用狀況,你應該在安全的時機主動釋放掉它們。
var url = URL.createObjectURL(blob); // 此時url的值,跟document繫結,所以每個頁面建立的字串均不同 // blob:https://developer.mozilla.org/defe53c2-2882-43c6-b275-db2a57959789
此時,我們在頁面中建立一個新<a>
標籤,點選即可下載我們想要的檔案:
<a href="blob:https://developer.mozilla.org/58702010-433d-4097-990f-e483d84cd02a" download="file.json">下載檔案連結</a>
FileReader
讀取Blob
資料
想要讀取Blob
資料的唯一方法是FileReader
。
FileReader
物件允許Web應用程式非同步讀取儲存在使用者計算機上的檔案(或原始資料緩衝區)的內容,使用File
或Blob
物件指定要讀取的檔案或資料。
其中File
物件可以是來自使用者在一個<input>
元素上選擇檔案後返回的FileList
物件,也可以來自拖放操作生成的DataTransfer
物件,還可以是來自在一個HTMLCanvasElement
上執行mozGetAsFile()
方法後返回結果。
該物件包含3個屬性:
FileReader.error
一個DOMException,表示在讀取檔案時發生的錯誤 。
FileReader.readyState
表示FileReader狀態的數字。取值如下:
常量名值描述 EMPTY0還沒有載入任何資料. LOADING1資料正在被載入. DONE2已完成全部的讀取請求.
FileReader.result
檔案的內容。該屬性僅在讀取操作完成後才有效,資料的格式取決於使用哪個方法來啟動讀取操作。
包含6個事件處理:onabort,onerror,onload,onloadstart,onloadend,onprogress
,這些不再詳細說明,因為FileReader
繼承自EventTarget
,所以所有這些事件也可以通過addEventListener
方法使用。
包含5個方法:
FileReader.abort()
中止讀取操作。在返回時,readyState屬性為DONE。
FileReader.readAsArrayBuffer()
開始讀取指定的 Blob中的內容, 一旦完成, result 屬性中儲存的將是被讀取檔案的 ArrayBuffer 資料物件.
FileReader.readAsBinaryString()
開始讀取指定的Blob中的內容。一旦完成,result屬性中將包含所讀取檔案的原始二進位制資料。
FileReader.readAsDataURL()
開始讀取指定的Blob中的內容。一旦完成,result屬性中將包含一個data: URL格式的字串以表示所讀取檔案的內容。
FileReader.readAsText()
開始讀取指定的Blob中的內容。一旦完成,result屬性中將包含一個字串以表示所讀取的檔案內容。
因此我們可以直接讀取Blob
物件的資料:
var reader = new FileReader(); reader.addEventListener("loadend", function() { console.log(reader.result); }); reader.readAsDataURL(blob); // 此時result的值 // data:application/json;base64,ewogICJoZWxsbyI6ICJ3b3JsZCIKfQ== reader.readAsText(blob); // 此時result的值 // { //"hello": "world" // }
下載圖片
除了下載手動生成的字串或物件,我們還能提供下載圖片的功能,一方面能用於支援Canvas
繪圖的儲存功能,一方面能提供批量下載圖片等高階功能。
除了瀏覽器自帶的右鍵儲存,我們還可以這麼做來下載圖片:
// 通過src獲取圖片的blob物件 function getImageBlob(url, cb) { var xhr = new XMLHttpRequest(); xhr.open("get", url, true); xhr.responseType = "blob"; xhr.onload = function() { if (this.status == 200) { cb(this.response); } }; xhr.send(); } let reader = new FileReader(); reader.addEventListener("loadend", function() { console.log(reader.result); }); getImageBlob('https://cdn.segmentfault.com/v-5c4ec07f/global/img/user-64.png', function(blob){ // 讀取來看下下載的內容 reader.readAsDataURL(blob); // 最終生成的字串 // data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAA... // 生成下載用的URL物件 let url = URL.createObjectURL(blob); // 生成一個a標籤,並模擬點選,即可下載,批量下載同理 let aDom = aDom = document.createElement('a'); aDom.href = url; aDom.download = 'download.json'; aDom.text = '下載檔案'; document.getElementsByTagName('body')[0].appendChild(aDom); aDom.click(); });
下載excel
檔案等
如果你明白了下載的原理,那麼所有的內容都能夠理解,只不過是轉換成對應的格式而已,當然,複雜格式的文件不需要你自己去配置,可以引入第三方庫,在excel
文件方面我選擇用tableExport庫
:
// 引入CDN檔案 'https://cdn.bootcss.com/xlsx/0.14.1/xlsx.core.min.js', 'https://cdn.bootcss.com/FileSaver.js/2014-11-29/FileSaver.min.js', 'https://cdn.bootcss.com/TableExport/5.2.0/js/tableexport.min.js' // 繫結下載事件,這個是我自己的場景下程式碼,可能不適合大家,具體的參考官方文件 const tableDom = $('#table'); $('.table-exportBtn', tableDom).on('click', function () { const tableExport = tableDom.tableExport({ formats: ['xlsx', 'txt'], filename: '表格下載', exportButtons: false }); const type = $(this).data().type; const exportData = tableExport.getExportData()[tableDom[0].id][type]; const {data, mimeType, filename, fileExtension} = exportData; tableExport.export2file(data, mimeType, filename, fileExtension); });
參考資料
- MDN-a:https://developer.mozilla.org...
- MDN-blob:https://developer.mozilla.org...
- 掘金-細說Web API中的Blob:https://juejin.im/post/59e35d...
- MDN-URL:https://developer.mozilla.org...
- MDN-FileReader:https://developer.mozilla.org...
- 部落格園-js 獲取圖片url的Blob值並預覽:https://www.cnblogs.com/tujia...
- tableExport文件:https://tableexport.v5.travis...