文件生成需要后台服务?前端就能搞定!前端生成可下载文件详解
文章内容
原理
Blob对象
MIME类型
构建下载链接
生成文件示例
生成txt
生成html
生成css
生成json
生成csv/excel
生成图
生成pdf
示例代码
一般而言,文件下载需要两个条件:
文件 文件地址(一个指向文件的链接)
这个文件可以是在服务器上的静态文件,也可以是服务器动态生成的。当然,也能由前端生成。以下为前端生成可下载文件的技术细节。
构建文件 Blob 对象
Blob
对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取。
Blob 由一个可选的字符串 type(通常是 MIME 类型)和 blobParts 组成 —— 一系列其他 Blob 对象,字符串和 BufferSource。
构造函数的语法为:
new Blob(blobParts, options);
blobParts
是Blob
/BufferSource
/String
类型的值的数组。options
可选对象:type
——Blob
类型,通常是 MIME 类型,例如image/png
,endings
—— 是否转换换行符,使Blob
对应于当前操作系统的换行符(\r\n
或\n
)。默认为"transparent"
(啥也不做),不过也可以是"native"
(转换)。
一般只用到options的type类型:
const file = new Blob([blobData], { type: filetype });
MIME 类型
媒体类型(通常称为 Multipurpose Internet Mail Extensions 或 MIME 类型 )是一种标准,用来表示文档、文件或字节流的性质和格式。当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
其通用结构为:
type/subtype
常见的类型有:
两种主要的 MIME 类型在默认类型中扮演了重要的角色:
text/plain
表示文本文件的默认值。一个文本文件应当是人类可读的,并且不包含二进制数据。application/octet-stream
表示所有其他情况的默认值。一种未知的文件类型应当使用此类型。浏览器在处理这些文件时会特别小心, 试图防止、避免用户的危险行为.
构建下载链接
我们可以在 Javascript 中动态创建一个链接,通过 link.click()
模拟一个点击,然后便自动下载了。
1 URL.createObjectURL 创建资源地址指向
URL.createObjectURL
取一个 Blob
,并为其创建一个唯一的 URL,形式为 blob:<origin>/<uuid>
。
浏览器内部为每个通过 URL.createObjectURL
生成的 URL 存储了一个 URL → Blob
映射。因此,此类 URL 很短,但可以访问 Blob
。
生成的 URL(即其链接)仅在当前文档打开的状态下才有效。它允许引用 <img>
、<a>
中的 Blob
,以及基本上任何其他期望 URL 的对象。
2 URL.revokeObjectURL 回收资源
不过它有个副作用。虽然这里有 Blob
的映射,但 Blob
本身只保存在内存中的。浏览器无法释放它。
在文档退出时(unload),该映射会被自动清除,因此 Blob
也相应被释放了。但是,如果应用程序寿命很长,那这个释放就不会很快发生。
因此,如果我们创建一个 URL,那么即使我们不再需要该 Blob
了,它也会被挂在内存中。
URL.revokeObjectURL(url)
从内部映射中移除引用,因此允许 Blob
被删除(如果没有其他引用的话),并释放内存。
在上面最后一个示例中,我们打算仅使用一次 Blob
,来进行即时下载,因此我们立即调用 URL.revokeObjectURL(link.href)
。
而在前一个带有可点击的 HTML 链接的示例中,我们不调用 URL.revokeObjectURL(link.href)
,因为那样会使 Blob
URL 无效。在调用该方法后,由于映射被删除了,因此该 URL 也就不再起作用了。
3 download 特性
download特性(attribute)强制浏览器下载而不是导航。
生成文件示例
生成.txt
生成.html
生成.css
生成.json
生成.csv
CSV是用UTF-8编码的,而EXCEL是ANSI编码,解决方法是在csv字符串前加上 \ufeff BOM 头。
生成图片
图像操作是通过 <canvas>
元素来实现的:
使用 canvas.drawImage 在 canvas 上绘制图像(或图像的一部分)。
调用 canvas 方法 .toBlob(callback, format, quality) 创建一个
Blob
,并在创建完成后使用其运行callback
。
这里推荐一个很好的工具,可以很方便将网页转换成图片。
html2canvas – Screenshots with JavaScript
html2canvas.js是一个将html dom转化成图片的 js 类库。
我用这个类库写个一个代码截图工具:
http://codeimg.mzh.ren/
生成PDF文件
跟图片一样,js生成PDF文件也是基于Canvas。推荐两个基于html2canvas的类库。
html2pdf.js | Client-side HTML-to-PDF rendering using pure JS.
jsPDF – HTML5 PDF Generator | Parallax
以jsPDF为例:
jsPDF生成的pdf中文字会乱码,可能是因为字体的原因。
(更多文件类型,进一步补充…)
示例代码
const $ = document.querySelector.bind(document)
function downFile(blob, fileName) {
const link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = fileName
link.click()
window.URL.revokeObjectURL(link.href)
}
const txtBtn = $('#txt')
txtBtn.onclick = () => {
let txtFile = new Blob(['Hello, world!'], { type: 'text/plain' })
downFile(txtFile, 'hello.txt')
}
const htmlBtn = $("#html");
htmlBtn.onclick = () => {
const html_string = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>码中人</h1>
</body>
</html>`;
let htmlFile = new Blob([html_string], { type: 'text/html' });
downFile(htmlFile, "index.html")
}
const cssBtn = $('#css');
cssBtn.onclick = () =>{
const css_string = `body {
margin: 0;
font-family: -apple-system,BlinkMacSystemFont,"Roboto",sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.editor-footer {
position: absolute;
bottom: 1.2em;
right: 1.4em;
width: 100%;
}
`;
const cssFile = new Blob([css_string], { type: 'text/css' });
downFile(cssFile,"style.css")
}
const jsonBtn = $("#json");
jsonBtn.onclick = () => {
const debug = { hello: "blob" };
const blob = new Blob([JSON.stringify(debug, null, '\t')], { type: 'application/json' });
downFile(blob, "debug.json");
}
const csvBtn = $('#csv');
csvBtn.onclick = () => {
const csvString = ["a,b,c", "1,2,3", "一,二,三", "木,头,人"].join("\n");
const blob = new Blob(["\ufeff" + csvString], { type: 'text/csv;charset=UTF-8' });
downFile(blob, "test.csv")
}
const imgBtn = $("#image");
imgBtn.onclick = () => {
window.open('http://codeimg.mzh.ren/','codeimg')
}
const pdfBtn = $('#pdf');
pdfBtn.onclick = () => {
const { jsPDF } = window.jspdf
const doc = new jsPDF()
doc.text('click to www.mzh.ren!', 66, 88)
const pdf_blob = new Blob([doc.output()], { type: 'application/pdf' })
downFile(pdf_blob,'jspdf.pdf');
}
参考资料
Blob Blob – Web API 接口参考 | MDN MIME 类型 – HTTP | MDN 常见 MIME 类型列表 – HTTP | MDN 你不知道的 Blob-前端开发博客 UTF-8 csv fix for Excel | Camille Hodoul
往期推荐