在后台的时候,经常学会遇到批量导出的场景;通常我们可以交由后端去处理,然而最近在开发中遇到了需要绘制 canvas 后再导出的场景;
# 方案
面对这样的需求,提出了以下几个方案:
方案一:后端绘制 canvas ,前端获取后端返回文件地址数组,然后遍历下载;
方案二:后端绘制 canvas ,接着对文件进行打包压缩处理,然后前端下载一个压缩文件;
方案三:后端绘制 canvas ,前端获取后端返回文件地址数组,然后遍历下载,接着前端来进行打包压缩处理。
方案四:前端绘制 canvas ,然后遍历下载。
方案五:前端绘制 canvas ,接着前端来进行打包压缩处理。
# 方案简单分析
从图片可以看出,直接进行批量下载,非常的难看;所以,未经打包压缩直接下载,显然不够优雅,方案一、方案四 out。
而后端绘制 canvas ,又不够灵活,方案二、方案三也宣布 out。
剩下的便是方案五了;下面就让我们一起看看如何实现吧。
# 实现
这就要请出本期的嘉宾 JSZip
和 FileSaver.js
了。
JSZip: 大家好,我是 JSZip, 是一个 javascript 库,用于创建、读取和编辑 .zip 文件,带有一个可爱而简单的API。这是我的简历 (opens new window)。请大家多多喜欢我。
FileSaver.js:好啊,我是 FileSaver,是一个在客户端保存文件的解决方案,适用 web 应用程序在客户端生成文件哦~ 康康我 (opens new window)
最后,还有我们的特殊嘉宾 qrcode
!
qrcode:很高兴见到大家,我是 qrcode ,我的本领是生成二维码并保存成各种格式,可以在服务器和客户端运行呢。我在这 (opens new window)
接下去,就让我们步入正题吧!让各位嘉宾与选手拿出他们的真本事。
只见, canvas
第一个站了出来,随着她的出现,编辑器上慢慢浮现出;
let canvas = document.createElement("CANVAS");
const ctx = canvas.getContext("2d");
canvas.height = 120;
canvas.width = 300;
ctx.fillStyle = "white";
ctx.fillRect(0, 0, 300, 120);
ctx.font = "16px 微软雅黑";
ctx.fillStyle = "red";
ctx.fillText(`name :sicker`, 130, 20);
ctx.fillText(`number :1024`, 130, 45);
ctx.fillText(`fen :200`, 130, 70);
ctx.fillStyle = "black";
ctx.fillText(`一个没啥用的demo`, 130, 110);
let base64 = canvas.toDataURL("image/png");
2
3
4
5
6
7
8
9
10
11
12
13
14
漂亮,我们的 canvas
选手,兔起鹘落间,已经在浏览器上画上了一个绝美的图卷;
然后,一旁的数据一看,就不满的叫嚷起来,「哼,没有我,终究是个死物」。
data
选手,手一挥,编辑器上就留下了一排数据;
data() {
return {
imgData: [
{
name: "sicker",
number: 1024,
fen: 200,
},
{
name: "linvkey",
number: 123,
fen: 123,
},
{
name: "XBlack",
number: 520,
fen: -52,
},
],
};
},
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
forEach
见自己心水的 canvas
面露难色,忙站了出来,他说:「遍历的事情就交给我吧」。
说话间,只见编辑器上刷刷出现了数行代码。不一会儿与 canvas
相得益彰。真不愧是老牌的选手了。
let canvas = document.createElement("CANVAS");
const ctx = canvas.getContext("2d");
this.imgData.forEach((e) => {
canvas.height = 120;
canvas.width = 300;
ctx.fillStyle = "white";
ctx.fillRect(0, 0, 300, 120);
ctx.font = "16px 微软雅黑";
ctx.fillStyle = "red";
ctx.fillText(`name :${e.name}`, 130, 20);
ctx.fillText(`number :${e.number}`, 130, 45);
ctx.fillText(`fen :${e.fen}`, 130, 70);
ctx.fillStyle = "black";
ctx.fillText(`一个没啥用的demo`, 130, 110);
let base64 = canvas.toDataURL("image/png");
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
果然, data
一看,竟是如此和谐,一时无话可说。只得退下;
然而文无第一,武无第二。这一对狗男女的配合虽然紧密无间,但是,终究无法折服所有人。
早已站在一侧的老牌强旅 image
悠悠然走上一步,道:「妙则妙矣,然任你多么精妙,还不是要依赖于我 image」。她指着 let base64 = canvas.toDataURL("image/png");
,缓缓将狗男女的弱点道了出来,紧接着,娇手一挥。编辑器也随着改变。
let canvas = document.createElement("CANVAS");
const ctx = canvas.getContext("2d");
this.imgData.forEach((e) => {
canvas.height = 120;
canvas.width = 300;
ctx.fillStyle = "white";
ctx.fillRect(0, 0, 300, 120);
ctx.font = "16px 微软雅黑";
ctx.fillStyle = "red";
ctx.fillText(`name :${e.name}`, 130, 20);
ctx.fillText(`number :${e.number}`, 130, 45);
ctx.fillText(`fen :${e.fen}`, 130, 70);
ctx.fillStyle = "black";
ctx.fillText(`一个没啥用的demo`, 130, 110);
let base64 = canvas.toDataURL("image/png");
let image = new Image();
image.src = base64;
document.body.appendChild(image);
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
「好好好」,却没想到,这次出来的竟是我们的嘉宾 3 人组。编辑器又是刷的一变。
var zip = new JSZip();
let canvas = document.createElement("CANVAS");
let qrcodeCanvas = document.createElement("CANVAS");
const ctx = canvas.getContext("2d");
this.imgData.forEach((e) => {
canvas.height = 120;
canvas.width = 300;
ctx.fillStyle = "white";
ctx.fillRect(0, 0, 300, 120);
// 绘制二维码
QRCode.toCanvas(
qrcodeCanvas,
`{"name":"${e.name}"}`,
{ width: 100, margin: 0 },
(err) => {
if (err) throw err;
}
);
// 将二维码 canvas 画布 绘入新的画布
ctx.drawImage(qrcodeCanvas, 10, 10, 100, 100);
ctx.font = "16px 微软雅黑";
ctx.fillStyle = "red";
ctx.fillText(`name :${e.name}`, 130, 20);
ctx.fillText(`number :${e.number}`, 130, 45);
ctx.fillText(`fen :${e.fen}`, 130, 70);
ctx.fillStyle = "black";
ctx.fillText(`一个没啥用的demo`, 130, 110);
let base64 = canvas.toDataURL("image/png");
let image = new Image();
image.src = base64;
base64 = base64.replace(/^data:image\/(png|jpg);base64,/, "");
document.body.appendChild(image);
// 将生成的 base64 对象置入 zip 对象中
zip.file(`${e.name}.png`, base64, { base64: true });
});
// 生成 zip 并打包为 example.zip
zip.generateAsync({ type: "blob" }).then(function (content) {
saveAs(content, "example.zip");
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
「一时技痒,献丑献丑!」
这一下,众人再也没有下场显圣之心,本场大赛风头最盛的竟是嘉宾三人组。众人悻悻然对冠军失去了兴趣;
最后由塞卡,订下这次赛事的主基调
batchDownload()
嘉宾们也兴致很高的留下了签名
import JSZip from "jszip";
import QRCode from "qrcode";
import { saveAs } from "file-saver";
2
3