前端批量导出canvas方案

前端批量导出canvas方案

最后修改时间:a day ago

在后台的时候,经常学会遇到批量导出的场景;通常我们可以交由后端去处理,然而最近在开发中遇到了需要绘制 canvas 后再导出的场景;

# 方案

面对这样的需求,提出了以下几个方案:

方案一:后端绘制 canvas ,前端获取后端返回文件地址数组,然后遍历下载;

方案二:后端绘制 canvas ,接着对文件进行打包压缩处理,然后前端下载一个压缩文件;

方案三:后端绘制 canvas ,前端获取后端返回文件地址数组,然后遍历下载,接着前端来进行打包压缩处理。

方案四:前端绘制 canvas ,然后遍历下载。

方案五:前端绘制 canvas ,接着前端来进行打包压缩处理。

# 方案简单分析

图 1

从图片可以看出,直接进行批量下载,非常的难看;所以,未经打包压缩直接下载,显然不够优雅,方案一、方案四 out。

而后端绘制 canvas ,又不够灵活,方案二、方案三也宣布 out。

剩下的便是方案五了;下面就让我们一起看看如何实现吧。

# 实现

这就要请出本期的嘉宾 JSZipFileSaver.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");
1
2
3
4
5
6
7
8
9
10
11
12
13
14

图 2

漂亮,我们的 canvas 选手,兔起鹘落间,已经在浏览器上画上了一个绝美的图卷;

然后,一旁的数据一看,就不满的叫嚷起来,「哼,没有我,终究是个死物」。

data 选手,手一挥,编辑器上就留下了一排数据;

data() {
  return {
    imgData: [
      {
        name: "sicker",
        number: 1024,
        fen: 200,
      },
      {
        name: "linvkey",
        number: 123,
        fen: 123,
      },
      {
        name: "XBlack",
        number: 520,
        fen: -52,
      },
    ],
  };
},
1
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");
});
1
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);
});
1
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");
});
1
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()
1

嘉宾们也兴致很高的留下了签名

import JSZip from "jszip";
import QRCode from "qrcode";
import { saveAs } from "file-saver";
1
2
3

图 3

- 全文完 -

留下一条留言?
默认颜色

主题颜色

标准颜色

更多颜色...