寫(xiě)在前面
在實(shí)際開(kāi)發(fā)過(guò)程中經(jīng)常會(huì)碰到用戶(hù)要下載或者導(dǎo)出一個(gè)文件的需求絮蒿。傳統(tǒng)的做法是在后端存儲(chǔ)或者即時(shí)生成一個(gè)文件來(lái)提供下載功能,這樣的優(yōu)勢(shì)是可以做權(quán)限控制叁鉴、方便數(shù)據(jù)二次處理土涝,但缺點(diǎn)是需要額外發(fā)起請(qǐng)求、增大服務(wù)端壓力幌墓、下載速度慢但壮。但隨著HTML5的標(biāo)準(zhǔn)發(fā)布,我大前端已經(jīng)完全可以獨(dú)立實(shí)現(xiàn)文件下載與導(dǎo)出啦~
利用a標(biāo)簽的 download 屬性下載文件
download屬性指示瀏覽器下載 URL而不是導(dǎo)航到它常侣,因此將提示用戶(hù)將其保存為本地文件蜡饵。如果屬性有一個(gè)值,那么此值將在下載保存過(guò)程中作為預(yù)填充的文件名(如果用戶(hù)需要胳施,仍然可以更改文件名)溯祸。此屬性對(duì)允許的值沒(méi)有限制,但是 / 和 \ 會(huì)被轉(zhuǎn)換為下劃線(xiàn)舞肆。大多數(shù)文件系統(tǒng)限制了文件名中的標(biāo)點(diǎn)符號(hào)焦辅,故此,瀏覽器將相應(yīng)地調(diào)整建議的文件名胆绊。
<a download="文件名" href="文件地址">下載測(cè)試</a>
需要注意的是:
- download 僅適用于同源 URL氨鹏,但是可以使用 blob: URL 和 data: URL。
- 如果 HTTP 頭中的
Content-Disposition
屬性賦予了一個(gè)不同于此屬性的文件名压状,HTTP 頭屬性?xún)?yōu)先于此屬性。 - 如果 HTTP 頭屬性
Content-Disposition
被設(shè)置為inline 即Content-Disposition='inline'
跟继,那么 Firefox 優(yōu)先考慮 HTTP 頭Content-Disposition
download 屬性种冬。
生成Data URLs 并下載文件
Data URL
即前綴為 data:
協(xié)議的URL,其允許內(nèi)容創(chuàng)建者向文檔中嵌入小文件舔糖。它 由四個(gè)部分組成:前綴(data:)娱两、指示數(shù)據(jù)類(lèi)型的MIME類(lèi)型、如果非文本則為可選的base64標(biāo)記金吗、數(shù)據(jù)本身十兢。
data:[<mediatype>][;base64],<data>
mediatype 是個(gè) MIME 類(lèi)型的字符串
例如 "image/jpeg" 表示 JPEG 圖像文件。
如果被省略摇庙,則默認(rèn)值為 text/plain;charset=US-ASCII
如果數(shù)據(jù)是文本類(lèi)型旱物,你可以直接將文本嵌入
如果是二進(jìn)制數(shù)據(jù),你可以將數(shù)據(jù)進(jìn)行base64編碼之后再進(jìn)行嵌入卫袒。
導(dǎo)出文件代碼示例:
//導(dǎo)出Json文件
exportJson(){
const downloadData = {
name:"April",
ager:"18",
hobby:"學(xué)習(xí)"
};
let dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(downloadData));
let downloadAnchorNode = document.createElement('a')
downloadAnchorNode.setAttribute("href", dataStr);
downloadAnchorNode.setAttribute("download", "文件名.json")
downloadAnchorNode.click();
downloadAnchorNode.remove();
},
生成blob: URL 并下載文件
Blob()
構(gòu)造函數(shù)返回一個(gè)新的 Blob 對(duì)象宵呛。 blob的內(nèi)容由參數(shù)數(shù)組中給出的值的串聯(lián)組成。
let aBlob = new Blob( array, options );
array
是一個(gè)由ArrayBuffer
, ArrayBufferView
, Blob
, DOMString
等對(duì)象構(gòu)成的 Array
夕凝,或者其他類(lèi)似對(duì)象的混合體宝穗,它將會(huì)被放進(jìn) Blob
户秤。DOMStrings會(huì)被編碼為UTF-8。
options
是一個(gè)可選的BlobPropertyBag
字典逮矛,它可能會(huì)指定如下兩個(gè)屬性:
-
type
鸡号,默認(rèn)值為 "",它代表了將會(huì)被放入到blob中的數(shù)組內(nèi)容的MIME類(lèi)型须鼎。 -
endings
膜蠢,默認(rèn)值為"transparent"
,用于指定包含行結(jié)束符\n
的字符串如何被寫(xiě)入莉兰。 它是以下兩個(gè)值中的一個(gè):"native"
挑围,代表行結(jié)束符會(huì)被更改為適合宿主操作系統(tǒng)文件系統(tǒng)的換行符,或者"transparent"
糖荒,代表會(huì)保持blob中保存的結(jié)束符不變 杉辙。
URL.createObjectURL()
靜態(tài)方法會(huì)創(chuàng)建一個(gè) DOMString,其中包含一個(gè)表示參數(shù)中給出的對(duì)象的URL捶朵。這個(gè) URL 的生命周期和創(chuàng)建它的窗口中的 document 綁定蜘矢。這個(gè)新的URL 對(duì)象表示指定的 File 對(duì)象或 Blob 對(duì)象。
objectURL = URL.createObjectURL(object);
導(dǎo)出文件代碼示例:
exportJson() {
const downloadData = {
name: "April",
ager: "18",
hobby: "學(xué)習(xí)"
};
let blob = new Blob(
[JSON.stringify(downloadData, null, 2)],
{type: 'application/json'});
let url = URL.createObjectURL(blob);
let downloadAnchorNode = document.createElement('a')
downloadAnchorNode.setAttribute("href", url);
downloadAnchorNode.setAttribute("download", "文件名.json")
downloadAnchorNode.click();
downloadAnchorNode.remove();
}
讀取上傳文件的數(shù)據(jù)
想要讀取Blob數(shù)據(jù)的唯一方法是FileReader综看。
FileReader
對(duì)象允許Web應(yīng)用程序異步讀取存儲(chǔ)在用戶(hù)計(jì)算機(jī)上的文件(或原始數(shù)據(jù)緩沖區(qū))的內(nèi)容品腹,使用 File
或 Blob
對(duì)象指定要讀取的文件或數(shù)據(jù)。
其中File
對(duì)象可以是來(lái)自用戶(hù)在一個(gè)<input>
元素上選擇文件后返回的FileList
對(duì)象,也可以來(lái)自拖放操作生成的 DataTransfer
對(duì)象,還可以是來(lái)自在一個(gè)HTMLCanvasElement
上執(zhí)行mozGetAsFile()
方法后返回結(jié)果红碑。
包含5個(gè)方法:
FileReader.abort()
中止讀取操作舞吭。在返回時(shí)蛋辈,readyState屬性為DONE轻专。FileReader.readAsArrayBuffer()
開(kāi)始讀取指定的 Blob中的內(nèi)容, 一旦完成, result 屬性中保存的將是被讀取文件的 ArrayBuffer 數(shù)據(jù)對(duì)象.FileReader.readAsBinaryString()
開(kāi)始讀取指定的Blob中的內(nèi)容根暑。一旦完成串稀,result屬性中將包含所讀取文件的原始二進(jìn)制數(shù)據(jù)襟诸。FileReader.readAsDataURL()
開(kāi)始讀取指定的Blob中的內(nèi)容煞躬。一旦完成瑟蜈,result屬性中將包含一個(gè)data: URL格式的字符串以表示所讀取文件的內(nèi)容爽哎。FileReader.readAsText()
開(kāi)始讀取指定的Blob中的內(nèi)容奕剃。一旦完成衷旅,result屬性中將包含一個(gè)字符串以表示所讀取的文件內(nèi)容。
將上傳的文件讀取為字符串的代碼示例
handleUpload(blob) {
// 新建一個(gè)FileReader
const reader = new FileReader()
// 讀取文件
reader.readAsText(blob, "UTF-8")
// 讀取完文件之后會(huì)回來(lái)這里
reader.onload = function (e) {
// 讀取文件內(nèi)容
const fileString = e.target.result
// 接下來(lái)可對(duì)文件內(nèi)容進(jìn)行處理
const myData = JSON.parse(fileString);
console.log(myData) // 打印讀取到的內(nèi)容
}
},
將上傳的文件讀取為URL格式的字符串的代碼示例
handleUpload(file) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function (e) {
const urlStr = reader.result
console.log(urlStr)
}
點(diǎn)擊下載圖片
雖然目前瀏覽器都支持保存圖片到本地的功能(右鍵>圖片另存為)但是實(shí)際開(kāi)發(fā)中會(huì)涉及到批量下載圖片纵朋、Canvas繪圖的保存功能柿顶,應(yīng)運(yùn)上面的知識(shí),我大前端也可以輕松實(shí)現(xiàn)倡蝙。代碼如下:
<button @click="downloadImg">下載圖片</button>
// 通過(guò)src獲取圖片的blob對(duì)象
getImageBlob(url, cb) {
let xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.responseType = "blob";
xhr.onload = function () {
if (this.status == 200) {
cb(this.response);
}
};
xhr.send();
},
// 點(diǎn)擊下載圖片
downloadImg(){
let reader = new FileReader();
this.getImageBlob('https://b-gold-cdn.xitu.io/v3/static/img/simplify-logo.3e3c253.svg', function(blob){
// 讀取來(lái)看下下載的內(nèi)容 最終生成的字符串
reader.readAsDataURL(blob);
// 生成下載用的URL對(duì)象
let url = URL.createObjectURL(blob);
// 生成一個(gè)a標(biāo)簽九串,并模擬點(diǎn)擊,即可下載,批量下載同理
let downloadAnchorNode = document.createElement('a')
downloadAnchorNode.setAttribute("href", url);
downloadAnchorNode.setAttribute("download", "下載圖片")
downloadAnchorNode.click();
downloadAnchorNode.remove();
})
},