写项目的时候有个需求是在vue的表格中,用户点击下载按钮,自动下载二维码,且二维码上下方展示一些信息。
起初我选用了简洁易写的qrcode.js2,代码如下
<el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="日期" align="center" prop="date" />
<el-table-column label="名称" align="center" prop="name" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改
</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除
</el-button>
<el-button size="mini" type="text" icon="el-icon-download" @click="createQRCode(scope.row)">导出二维码
</el-button>
</template>
</el-table-column>
<div id="qrcode" ref="qrCodeDiv" style="width: 300px;height: 300px">
</div>
</el-table>
createQRCode(row) {
const prefix = this.qrPrefix
document.getElementById("qrcode").innerHTML = ""
let qrcode = new QRCode(this.$refs['qrCodeDiv'], {
text: prefix + '' + row.id,
width: 200, //二维码的宽度
height: 200, //二维码的高度
colorDark: "#666666", // 二维码的深色部分
colorLight: "#ffffff", //二维码的浅色部分
correctLevel: QRCode.CorrectLevel.H,//纠错级别,L,M,Q,H,由低到高
})
this.downloadQRCode(row.Name)
},
downloadQRCode(name) {
let qrcode = document.getElementById('qrcode');
let img = qrcode.getElementsByTagName('img')[0];
img.onload = function () {
this.imgUrl = img.getAttribute("src");
let link = document.createElement("a");
link.setAttribute("href", this.imgUrl);//指定href
link.setAttribute("download", name+ '.png')//指定文件名
link.click();
}
},
使用qrcode.js2生成二维码相对简单易操作,但是同时其提供的api较少,所以很难满足需求。
为了实现需求,我尝试了vue-qr和qrcode.js,最终选择了qrcode.js,参考了其他博主的一些文章与代码,改进后的代码如下
<el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="日期" align="center" prop="date" />
<el-table-column label="名称" align="center" prop="name" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改
</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除
</el-button>
<el-button size="mini" type="text" icon="el-icon-download" @click="createQRCode(scope.row)">导出二维码
</el-button>
</template>
</el-table-column>
<div id="qrcode" :title="qrText">
<div class="qrcode_box">
<img class="qrcode_canvas" id="qrcode_canvas" ref="qrcode_canvas" alt="二维码" />
<img v-if="qrLogo" class="qrcode_logo" ref="qrcode_logo" :src="qrLogo" alt="logo" />
<canvas :width="qrSize" :height="qrSize" class="canvas" ref="canvas"></canvas>
</div>
</div>
</el-table>
import QRCode from "qrcode";
export default {
name: "qrsign",
props: {
qrUrl: {
type: String,
default: "https://www.baidu.com"
},
qrSize: {
type: Number,
default: 300
},
qrText: {
default: "百度,百度,百度"
},
qrLogo: {
type: String,
default: logo
},
qrLogoSize: {
type: Number,
default: 40
},
qrTextSize: {
type: Number,
default: 14
}
},
methods: {
createQRCode(row) {
const prefix = this.qrPrefix
this.qrText = row.date+" "+row.name//底部文字
let topText = row.name//顶部文字
this.qrUrl = prefix+ row.id//url,二维码内容,或跳转链接
let qrcode_canvas = this.$refs.qrcode_canvas;
let qrcode_logo = this.$refs.qrcode_logo;
let canvas = this.$refs.canvas;
const that = this;
QRCode.toDataURL(
this.qrUrl,
{ errorCorrectionLevel: "H" },
(err, url) => {
qrcode_canvas.src = url;
// 画二维码里的logo// 在canvas里进行拼接
let ctx = canvas.getContext("2d");
setTimeout(() => {
//使用setTimeout变为异步
//获取图片
ctx.drawImage(qrcode_canvas, 0, 0, that.qrSize, that.qrSize);
if (that.qrLogo) {
//设置logo大小
//设置获取的logo将其变为圆角以及添加白色背景
ctx.fillStyle = "#fff";
ctx.beginPath();
let logoPosition = (that.qrSize - that.qrLogoSize) / 2; //logo相对于canvas居中定位
let h = that.qrLogoSize + 10; //圆角高 10为基数(logo四周白色背景为10/2)
let w = that.qrLogoSize + 10; //圆角宽
let x = logoPosition - 5;
let y = logoPosition - 5;
let r = 5; //圆角半径
ctx.moveTo(x + r, y);
ctx.arcTo(x + w, y, x + w, y + h, r);
ctx.arcTo(x + w, y + h, x, y + h, r);
ctx.arcTo(x, y + h, x, y, r);
ctx.arcTo(x, y, x + w, y, r);
ctx.closePath();
ctx.fill(); qrcode_logo.onload = function () {
ctx.drawImage(
qrcode_logo,
logoPosition,
logoPosition,
that.qrLogoSize,
that.qrLogoSize
);
}
}
if (that.qrText) {
//设置字体
let fpadd = 10; //规定内间距
ctx.font = "bold " + that.qrTextSize + "px Arial";
let tw = ctx.measureText(that.qrText).width; //文字真实宽度
let ftop = that.qrSize - that.qrTextSize; //根据字体大小计算文字top
let fleft = (that.qrSize - tw) / 2; //根据字体大小计算文字left
let tp = that.qrTextSize / 2; //字体边距为字体大小的一半
ctx.fillStyle = "#fff";
ctx.fillRect(
fleft - tp / 2,
ftop - tp / 2,
tw + tp,
that.qrTextSize + tp
);
ctx.textBaseline = "top"; //绘制文本时的文本基线
ctx.fillStyle = "#333";
ctx.fillText(that.qrText, fleft, ftop);//canvas填充文字
}
if (topText) {
//设置字体
let fpadd = 10; //内间距
ctx.font = "bold " + that.qrTextSize + "px Arial";
let tw = ctx.measureText(topText).width; //文字真实宽度
let ftop = 5
let fleft = (that.qrSize - tw) / 2; //根据字体大小计算文字left
let tp = that.qrTextSize / 2; //字体边距为字体大小的一半
ctx.fillStyle = "#fff";
ctx.fillRect(
fleft - tp / 2,
ftop - tp / 2,
tw + tp,
that.qrTextSize + tp
);
ctx.textBaseline = "top"; //绘制文本时的文本基线
ctx.fillStyle = "#333";
ctx.fillText(topText, fleft, ftop);//canvas填充文字
}
qrcode_canvas.src = canvas.toDataURL();
this.downloadQRCode(qrcode_canvas,row.name)
}, 0);
}
);
},
downloadQRCode(image,name) {
let img = image
img.onload = function () {
this.imgUrl = img.getAttribute("src");
let link = document.createElement("a");
link.setAttribute("href", this.imgUrl);
link.setAttribute("download", name + '.png')
link.click();
}
}
}
};