vue 生成单/多个二维码含LOGO图片并下载


前言

需求背景:根据table中的数据,下载对应的二维码,并需在二维码下方添加编号和地址。实现效果如下图↓

在这里插入图片描述


一、实现思路

  1. 通过qrcodejs2插件生成二维码
  2. 通过html2canvas插件对页面指定区域进行图片生成
  3. 通过JSZip插件对生成的图片进行压缩
  4. 通过FileSaver插件对生成的图片进行导出成压缩文件格式!

二、下载相应库

import QRCode from 'qrcodejs2';
import html2canvas from "html2canvas"; //生成图片
import JSZip from "jszip"; //文件压缩
import FileSaver from "file-saver"; //导出文件

三、封装代码

  • template

代码如下:

<template>
  <div ref="html2canvasRef" class="QRCodeBox">
    <div :id="id" :ref="id" class="QRCode"></div>
    <div v-if="QRCodeInfo.title" class="QRCode_title">{{ QRCodeInfo.title }}</div>
  </div>
</template>
  • style

代码如下:

.QRCodeBox {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 200px;
  height: 200px;
  position: fixed;
  margin-top: -99999999999999999px;
  background: transparent;

  .QRCode {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
  }

  .QRCode_id, .QRCode_title {
    margin-bottom: 15px;
    font-size: 12px;
  }
}
  • js
<script>
import QRCode from 'qrcodejs2';
import html2canvas from "html2canvas"; //生成图片
import JSZip from "jszip"; //文件压缩
import FileSaver from "file-saver"; //导出文件

export default {
  data() {
    return {
      qrcode: '',
      QRCodeInfo: {},
      QRCodeList: []
    }
  },
  props: {
    id: {
      type: String,
      default: "QRCode",
      required: true
    },
    width: {
      type: String | Number,
      default: 150
    },
    height: {
      type: String | Number,
      default: 150
    },
    colorDark: {
      type: String,
      default: '#000000'
    },
    colorLight: {
      type: String,
      default: '#ffffff'
    },
    logoUrl: {
      type: String,
      default: ''
    },
    zipName: {
      type: String,
      default: '二维码.zip'
    },
    isBatchDownload: {
      type: Boolean,
      default() {
        return false
      }
    }
  },
  watch: {
    QRCodeList(QRCodeList) {
      this.list = QRCodeList
    }
  },
  mounted() {
  },
  methods: {
    QRCodeInit(data) {
      this.QRCodeInfo = data;

      return new Promise((resolve) => {
        this.qrcode = new QRCode(this.$refs[this.id], {
          text: data.id,
          width: this.width,
          height: this.height,
          colorDark: this.colorDark,
          colorLight: this.colorLight,
          correctLevel: QRCode.CorrectLevel.H,
          margin: 5,
          type: "image/png"
        });
        if (this.logoUrl) {
          let canvas = this.qrcode._el.getElementsByTagName("canvas")[0];
          let img = this.qrcode._el.getElementsByTagName("img")[0];
          let ctx = canvas.getContext("2d");

          let logo = new Image();
          logo.crossOrigin = "Anonymous";
          logo.src = this.logoUrl;

          logo.onload = () => {
            let codeWidth = (this.width * 0.8) / 2;
            let codeHeight = (this.height * 0.8) / 2;
            ctx.drawImage(logo, codeWidth, codeHeight, this.width * 0.2, this.height * 0.2);
            img.src = canvas.toDataURL();
            resolve(this.qrcode);
          }
        } else {
          resolve(this.qrcode);
        }

      })
    },
    removeCode() {
      if (this.qrcode) {
        this.$refs[this.id].innerHTML = ''
      }
    },
    // base64 转 二进制流(blob)
    dataURLtoBlob(dataUrl) {
      let arr = dataUrl.split(","),
          mime = arr[0].match(/:(.*?);/)[1],
          bstr = atob(arr[1]),
          n = bstr.length,
          u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new Blob([u8arr], {
        type: mime,
      });
    },

    async batchDownload(QRCodeList = []) {
      this.QRCodeList = QRCodeList;

      const imgList = []; //保存生成图片
      for (let i = 0; i < QRCodeList.length; i++) {
        await this.QRCodeInit(QRCodeList[i]);
        await html2canvas(this.$refs.html2canvasRef, {
          backgroundColor: null,
          useCORS: true,
          allowTaint: true,
          scale: 1,
        }).then((canvas) => {
          this.removeCode(); //图片生成完成时删除图片
          let url = canvas.toDataURL("image/png");
          if (this.isBatchDownload) {
            imgList.push({url, name: QRCodeList[i].title});
            //判断当生成的图片和要生成的数据长度相等时调用压缩函数
            if (imgList.length === QRCodeList.length) {
              this.imageCompress(imgList);
            }
          } else {
            const time = new Date().getTime();
            const title = `${time} -【${QRCodeList[i].title}】二维码.png`;
            let a = document.createElement("a");
            a.href = url;
            a.download = title;
            a.click();
          }
        }).catch(err => {
          console.log(err)
        });
      }
    },

    // 压缩转码
    imageCompress(imgList) {
      let zip = new JSZip();
      let index = 0;

      for (let i = 0; i < imgList.length; i++) {
        index++;
        let blob = this.dataURLtoBlob(imgList[i].url); //转二进制
        const time = new Date().getTime();
        const title = `${time} -【${imgList[i].name}】二维码.png`;
        zip.file(title, blob, {blob: true});
        if (index === imgList.length) {
          zip.generateAsync({type: "blob"}).then(
              (blob) => {
                FileSaver.saveAs(blob, this.zipName);
              }
          ).catch(() => {
          });
        }
      }
    },
  },

}

四、效果

  • 单个下载
    在这里插入图片描述

  • 批量下载
    在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笑看、人世间@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值