写在前面
在实际开发过程中经常会碰到用户要下载或者导出一个文件的需求。传统的做法是在后端存储或者即时生成一个文件来提供下载功能,这样的优势是可以做权限控制、方便数据二次处理,但缺点是需要额外发起请求、增大服务端压力、下载速度慢。但随着HTML5的标准发布,我大前端已经完全可以独立实现文件下载与导出啦~
利用a标签的 download 属性下载文件
download属性指示浏览器下载 URL而不是导航到它,因此将提示用户将其保存为本地文件。如果属性有一个值,那么此值将在下载保存过程中作为预填充的文件名(如果用户需要,仍然可以更改文件名)。此属性对允许的值没有限制,但是 / 和 \ 会被转换为下划线。大多数文件系统限制了文件名中的标点符号,故此,浏览器将相应地调整建议的文件名。
<a download="文件名" href="文件地址">下载测试</a>
需要注意的是:
- download 仅适用于同源 URL,但是可以使用 blob: URL 和 data: URL。
- 如果 HTTP 头中的
Content-Disposition
属性赋予了一个不同于此属性的文件名,HTTP 头属性优先于此属性。 - 如果 HTTP 头属性
Content-Disposition
被设置为inline 即Content-Disposition='inline'
,那么 Firefox 优先考虑 HTTP 头Content-Disposition
download 属性。
生成Data URLs 并下载文件
Data URL
即前缀为 data:
协议的URL,其允许内容创建者向文档中嵌入小文件。它 由四个部分组成:前缀(data:)、指示数据类型的MIME类型、如果非文本则为可选的base64标记、数据本身。
data:[<mediatype>][;base64],<data>
mediatype 是个 MIME 类型的字符串
例如 "image/jpeg" 表示 JPEG 图像文件。
如果被省略,则默认值为 text/plain;charset=US-ASCII
如果数据是文本类型,你可以直接将文本嵌入
如果是二进制数据,你可以将数据进行base64编码之后再进行嵌入。
导出文件代码示例:
//导出Json文件
exportJson(){
const downloadData = {
name:"April",
ager:"18",
hobby:"学习"
};
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()
构造函数返回一个新的 Blob 对象。 blob的内容由参数数组中给出的值的串联组成。
let aBlob = new Blob( array, options );
array
是一个由ArrayBuffer
, ArrayBufferView
, Blob
, DOMString
等对象构成的 Array
,或者其他类似对象的混合体,它将会被放进 Blob
。DOMStrings会被编码为UTF-8。
options
是一个可选的BlobPropertyBag
字典,它可能会指定如下两个属性:
-
type
,默认值为 "",它代表了将会被放入到blob中的数组内容的MIME类型。 -
endings
,默认值为"transparent"
,用于指定包含行结束符\n
的字符串如何被写入。 它是以下两个值中的一个:"native"
,代表行结束符会被更改为适合宿主操作系统文件系统的换行符,或者"transparent"
,代表会保持blob中保存的结束符不变 。
URL.createObjectURL()
静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。
objectURL = URL.createObjectURL(object);
导出文件代码示例:
exportJson() {
const downloadData = {
name: "April",
ager: "18",
hobby: "学习"
};
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();
}
读取上传文件的数据
想要读取Blob数据的唯一方法是FileReader。
FileReader
对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File
或 Blob
对象指定要读取的文件或数据。
其中File
对象可以是来自用户在一个<input>
元素上选择文件后返回的FileList
对象,也可以来自拖放操作生成的 DataTransfer
对象,还可以是来自在一个HTMLCanvasElement
上执行mozGetAsFile()
方法后返回结果。
包含5个方法:
FileReader.abort()
中止读取操作。在返回时,readyState属性为DONE。FileReader.readAsArrayBuffer()
开始读取指定的 Blob中的内容, 一旦完成, result 属性中保存的将是被读取文件的 ArrayBuffer 数据对象.FileReader.readAsBinaryString()
开始读取指定的Blob中的内容。一旦完成,result属性中将包含所读取文件的原始二进制数据。FileReader.readAsDataURL()
开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容。FileReader.readAsText()
开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个字符串以表示所读取的文件内容。
将上传的文件读取为字符串的代码示例
handleUpload(blob) {
// 新建一个FileReader
const reader = new FileReader()
// 读取文件
reader.readAsText(blob, "UTF-8")
// 读取完文件之后会回来这里
reader.onload = function (e) {
// 读取文件内容
const fileString = e.target.result
// 接下来可对文件内容进行处理
const myData = JSON.parse(fileString);
console.log(myData) // 打印读取到的内容
}
},
将上传的文件读取为URL格式的字符串的代码示例
handleUpload(file) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function (e) {
const urlStr = reader.result
console.log(urlStr)
}
点击下载图片
虽然目前浏览器都支持保存图片到本地的功能(右键>图片另存为)但是实际开发中会涉及到批量下载图片、Canvas绘图的保存功能,应运上面的知识,我大前端也可以轻松实现。代码如下:
<button @click="downloadImg">下载图片</button>
// 通过src获取图片的blob对象
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();
},
// 点击下载图片
downloadImg(){
let reader = new FileReader();
this.getImageBlob('https://b-gold-cdn.xitu.io/v3/static/img/simplify-logo.3e3c253.svg', function(blob){
// 读取来看下下载的内容 最终生成的字符串
reader.readAsDataURL(blob);
// 生成下载用的URL对象
let url = URL.createObjectURL(blob);
// 生成一个a标签,并模拟点击,即可下载,批量下载同理
let downloadAnchorNode = document.createElement('a')
downloadAnchorNode.setAttribute("href", url);
downloadAnchorNode.setAttribute("download", "下载图片")
downloadAnchorNode.click();
downloadAnchorNode.remove();
})
},