前端批量生成二维码并打包下载
项目中遇到一个紧急需求在没有后端配合的情况下,前端独自实现生成二维码并打包下载
生成二维码:下载 qrcodejs2
批量打包下载:下载 JSZip 和 FileSaver
对二维码进行二次加工:html2canvas
首先项目中分别引入
import QRCode from 'qrcodejs2';
import JSZip from 'jszip';
import FileSaver from 'file-saver';
由于QRCode只是生成了一个二维码,
产品这边嫌太单调让做二次加工,需要带上需要生成二维码的一下文本信息,
所以用到了html2canvas来将一个dom转成图片进行下载(要是大佬们有什么好的方法请告诉我,我实在不知道应该怎么弄只能选这种最笨的方法了QAQ)
接下来就是生成二维码:
生成二维码首先要认识到其实只是将一个你需要跳转的url给转成二维码而已,所以你需要一个跳转的url(最好是短链接,长链接的话会导致打点太密集有可能微信扫不出来)
你要是短链接的话可以直接使用不是的话最好转换一下防止扫不出来的问题
// 生成二维码
bindQRCode(codeurl, index) {
// eslint-disable-next-line no-new
new QRCode(this.$refs.qrcode.children[index].children[0], {
// 二维码宽度,单位像素
width: 450,
// 二维码高度,单位像素
height: 450,
// 二维码内容:二维码扫描之后访问的地址
text: codeurl,
// 前景色
colorDark: '#000000',
// 背景色
colorLight: '#ffffff',
// 容错级别,
correctLevel: QRCode.CorrectLevel.H,
});
// 关闭loading
this.loading = false;
// 显示下载按钮
this.HasDatacodeShow = true;
},
this.$refs.qrcode.children[index].children[0]这个东西是你二维码生成的位置
由于我这里是循环生成的需要索引
// 打包下载
packageImages() {
console.log('进入到打包下载');
// const that = this;
this.stationCanvas = [];
// eslint-disable-next-line no-plusplus
document.getElementsByClassName('codeBox').forEach((item, index) => {
html2canvas(document.getElementById(`codeimg${index}`)).then((canvas) => {
const url = canvas.toDataURL();
const Obj = {
url: item.children[0].getAttribute('title'),
src: url,
};
// eslint-disable-next-line no-shadow
this.shortUrlList.forEach((item) => {
if (item.shorturl === Obj.url) {
// eslint-disable-next-line no-param-reassign
item.imgSrc = url;
}
});
this.stationCanvas.push(Obj);
// 这里才是下载的地方,上面的方法是将通过二次加工后的赋值的操作
if (this.stationCanvas.length === this.shortUrlList.length) {
const zip = new JSZip();
const cache = {};
const arr = this.shortUrlList;
// eslint-disable-next-line no-shadow
arr.forEach((item) => {
// 设置生成的文件名,并且直接生成的二维码是base64二次加工过后的也是base64
const fileName = item.address.split('东港区')[1] + item.name;
zip.file(`${fileName}.png`, item.imgSrc.substring(22), { base64: true });
cache[fileName] = item.imgSrc;
});
zip.generateAsync({ type: 'blob' }).then((content) => {
this.loading = false;
FileSaver.saveAs(content, '二维码.zip');//这里设置压缩包的名称
this.$nextTick(() => {
//这里是由于我有分页操作要是不清空前一页的数据会导致后来生成的和之前的二维码重叠这样二次加工的就会错误
this.shortUrlList = [];
});
});
}
});
});
},
用html2canvas做二次加工会有个问题是html2canvas是个异步方法,而且会动态创建iframe然后销毁,要是大量的数据会导致内存泄漏,逼不得已加了分页来导出,要是大佬们有什么好的建议还请告诉我QAQ~
下面放一下页面结构~样式就不放了
<template>
<div
id="exportBox"
v-loading="loading"
:element-loading-text="loadingtext"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
>
<!-- <div class="title">日照智慧药房门店二维码导出系统</div> -->
<div class="contentBox">
<div class="cityBox">
<div class="ChooseCode">
<el-select
v-model="chooseArea"
placeholder="请选择区域"
style="width:200px;margin-right:20px"
@change="ChangeArea"
>
<el-option v-for="item in cities" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
<el-select
v-model="chooseStreet"
placeholder="请选择街道"
style="width:200px;margin-right:20px"
@change="ChangeStreet"
>
<el-option v-for="item in Strees" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
<el-select
v-model="chooseCommunity"
placeholder="请选择社区"
style="width:200px;"
@change="ChangeCommunity"
>
<el-option v-for="item in Community" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</div>
<div class="ChooseTime">
<el-date-picker
v-model="hasChooseDate"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd HH:mm:ss"
@change="ChangeTimeData"
>
</el-date-picker>
</div>
</div>
<div class="exportButton">
<el-button type="primary" @click="clickecport">生成二维码</el-button>
<el-button v-show="HasDatacodeShow" type="primary" @click="clickeexportcode"
>下载</el-button
>
</div>
<el-pagination
background
layout="prev, pager, next"
:total="AllTotals"
:page-size="50"
@current-change="ChangeCurrent"
>
</el-pagination>
<div id="qrcodeBox" ref="qrcode" v-show="qrcodeBoxShow">
<div
class="codeBox"
v-for="(item, index) in shortUrlList"
:key="index"
:id="'codeimg' + index"
ref="qrc"
>
<div class="codeImgbox" ref="BoxImgContent" :id="'codeImgbox' + index"></div>
<div class="codeStation">
<span class="address storeName">{{ item.address }}</span>
<span class="storeName">{{ item.name }}</span>
</div>
</div>
</div>
</div>
</div>
</template>