Skip to content

平台二维码生成以及需要注意事项

问题原因

  • 网页端生成的二维码,部分功能中存在移动端和网页端进行交互的场景,由于公司移动端使用的二维码识别库,识别率不高,经常会出现二维码识别失败的问题。所以我们在生成二维码的时候,需要将二维码的识别率提高。

解决方案

提高识别率的方法如下:

  1. 生成二维码的时候,添加logo或者文字有遮挡的情况,设置二维码的容错率。
  2. 生成二维码的时候,给二维码添加一个白色留边。

参考链接

实现代码

  • 由于平台使用的是qrcodejs2二维码插件, 就以此为例,其他插件也可以参考。
vue
<template>
	<el-dialog :title="title" :visible.sync="dialogVisible" v-dialog-loading="pageLoad" width="45em" center @closed="closed" :close-on-click-modal="false">
		<div class="qr-code">
			<el-row :gutter="10" class="qrcode-title">
				<el-col>
					<span>{{ subTitle }}</span>
				</el-col>
			</el-row>
			<el-row :gutter="10" class="qrcode-photo">
				<el-col>
					<div id="qrcode" class="qrcode" ref="qrcode"></div>
				</el-col>
			</el-row>
		</div>
        <span slot="footer" class="dialog-footer">
            <el-button class="lb-btn lb-btn-primary" @click="downloadQRCode()">保存二维码</el-button>
        </span>
	</el-dialog>
</template>
<script>
import QRCode from 'qrcodejs2';
export default {
    name: 'QRCode',
	props: {
		title: { // 弹框标题
			type: String,
			required: true,
		},
		subTitle: { // 提示文字
			type: String,
			default: '',
		},
	},
	data() {
		return {
			dialogVisible: false,
			btnLoad: false,
			pageLoad: false,
			qrcode: {},
			params: {},
		};
	},
    methods: {
        closed() {
			this.btnLoad = false;
			this.qrcode.clear(); // 清除二维码
			this.params = {};
		},
		async open(item) {
			this.dialogVisible = true;
            this.params = item;
            await this.$nextTick();
			this.creatQrCode(this.params.text, true);
		},
        // 生成二维码 
        creatQrCode(text, haveLogo) {
			this.$refs.qrcode.innerHTML = ''; //清除二维码方法一
			this.qrcode = new QRCode(this.$refs.qrcode, {
				text: text, //页面地址 ,如果页面需要参数传递请注意哈希模式#
				width: 200,
				height: 200,
				colorDark: '#000000',
				colorLight: '#ffffff',
				correctLevel: QRCode.CorrectLevel.H, // 容错级别,可配置L M Q H  H为最高
            });
            this.qrcode._el.title = '';
            
            /*** 由于插件生成的二维码图片不带边框,所以需要自己添加一个白色边框,这里使用canvas重绘 ***/
            // 获取插件生成的二维码canvas元素
            var canvas = this.qrcode._el.getElementsByTagName('canvas')[0];
            // 创建一个新的canvas元素,并设置它的宽度和高度,以及边框的宽度
            var borderCanvas = document.createElement('canvas');
            borderCanvas.width = canvas.width + 10; // 设置为比二维码canvas元素宽度多10个像素的宽度
            borderCanvas.height = canvas.height + 10;// 设置为比二维码canvas元素高度多10个像素的高度
            var ctx = borderCanvas.getContext('2d');
            // 绘制白色背景
            ctx.fillStyle = "#ffffff";
            ctx.fillRect(0, 0, borderCanvas.width, borderCanvas.height);
            // 将生成的二维码canvas元素绘制在新的canvas元素中心,形成边框
            ctx.drawImage(canvas, (borderCanvas.width - canvas.width) / 2, (borderCanvas.height - canvas.height) / 2);
            // 将生成的带有边框的二维码canvas元素插入到页面中 
            this.$refs.qrcode.appendChild(borderCanvas);
            // 判断是否需要插入logo图标
            if(haveLogo) {
                // 二维码中心插入logo图标
                let logo = new Image();
                logo.setAttribute('crossOrigin', 'Anonymous');
                logo.src = localStorage.webFileURL + '/resource/app/static/image/jgyl-logo.png';
                logo.style.padding = '5px';
                logo.onload = () => {
                    let qrImg = this.qrcode._el.getElementsByTagName('img')[0];
                    let canvas = this.qrcode._el.getElementsByTagName('canvas')[1];
                    canvas.style.display = 'inline-block';
                    let ctx = canvas.getContext('2d');
                    
                    // 绘制logo图标白色边框
                    ctx.fillStyle = "#FFFFFF";
                    ctx.fillRect((210 - 210 / 3.7) / 2 - 4, (210 - 210 / 3.7) / 2 - 4, 210 / 3.7 + 8, 210 / 3.7 + 8)
                    // 设置logo的大小为二维码图片缩小3.7倍,第二与第三参数为logo的左上角坐标在二维码的位置
                    ctx.drawImage(logo, (210 - 210 / 3.7) / 2, (210 - 210 / 3.7) / 2, 210 / 3.7, 210 / 3.7)
                    qrImg.src = canvas.toDataURL();
                    qrImg.style.display = 'none'; // 隐藏原先插件生成的二维码图片
                }
            } else {
                // 隐藏原先插件生成的二维码图片
                let qrImg = this.qrcode._el.getElementsByTagName('img')[0];
                setTimeout(() => { // 这里需要使用定时器,否则会出现无法设置 display 属性隐藏的情况
                    qrImg.style.display = 'none';
                }, 50)
            }
            
        },
        // 下载二维码
        downloadQRCode() {
            let canvas = this.qrcode._el.getElementsByTagName('canvas')[1]
            let imgUrl = canvas.toDataURL('image/png');
            let a = document.createElement('a');
            a.href = imgUrl;
            a.download = '二维码.png';
            a.click();
        }
    },
};
</script>
<style lang="less" scoped>
.qr-code {
	.qrcode-title {
		margin-bottom: 1.5em;
		text-align: center;
		line-height: 2em;
		color: #ccc;
	}

	.qrcode-photo {
		.qrcode {
			margin-bottom: 1em;
			margin: auto;
			height: 15em;
			width: 15em;
		}

		margin-bottom: 1em;

		/deep/ img {
			margin: auto;
		}
	}

	.qrcode-refresh-btn {
		margin-bottom: 1em;
		text-align: center;

		.refresh-btn {
			margin-right: 1em;
		}
	}

	.qrcode-tips {
		margin-bottom: 1em;
		text-align: center;
        line-height: 2em;
		color: red;
        .tips {
            margin-left: 7em;
            text-align: left;
        }
        .download-tips {
            cursor: pointer;
        }
	}
}
</style>