实现

afQrcode.vue

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
<template>
<div class="-qrcode">
<div class="qrcode-box">
<canvas :width="imgWidth" :height="imgWidth" ref="canvas" id="canvas"></canvas>
</div>
<img :src="dataUrl" :alt="downloadTitle" :title="downloadTitle" />
</div>
</template>

<script>
import QRCode from 'qrcode';
const TYPES = ['image/png', 'image/jpeg', 'image/webp'];

export default {
name: 'iccQrcode',
props: {
imgMargin: {
type: Number,
default: 2,
},
// 二维码实际大小
imgWidth: {
type: Number,
default: 400,
},
type: {
type: String,
validator: type => TYPES.includes(type),
default: 'image/png',
},
url: {
type: String,
default: '',
},
// 下载名称
downloadTitle: {
type: String,
default: '二维码',
},
// 显示中间logo url
logoUrl: {
type: String,
default: '',
},
},
data() {
return {
dataUrl: '',
qrLogoSize: 80, //logo size
};
},
watch: {
url(val) {
if (val) {
this.toDataURL();
} else {
this.dataUrl = '';
}
},
},
mounted() {
this.url && this.toDataURL();
},

methods: {
downLoadImg() {
if (!this.dataUrl) return;
this.downloadFile({
type: 'link',
fileType: 'png',
title: this.downloadTitle,
link: this.dataUrl,
});
},
toDataURL() {
QRCode.toDataURL(this.url, { width: this.imgWidth, margin: this.imgMargin })
.then(dataUrl => {
this.dataUrl = dataUrl;
if (this.logoUrl) {
this.$nextTick(() => {
this.makeCode(dataUrl);
});
}
})
.catch(err => this.$emit('error', err));
},
makeCode(dataUrl) {
const canvas = this.$refs.canvas;
const that = this;
// 生成二维码-img
const qrCodeImg = new Image();
// 生成logo-img
const logoImg = new Image();
// 画二维码里的logo 在canvas里进行拼接
const ctx = canvas.getContext('2d');
qrCodeImg.src = dataUrl;
qrCodeImg.onload = () => {
// 绘制二维码
ctx.drawImage(qrCodeImg, 0, 0, that.imgWidth, that.imgWidth);
//设置logo大小 设置获取的logo将其变为圆角以及添加白色背景
ctx.fillStyle = '#fff';
ctx.beginPath();
const logoPosition = (that.imgWidth - that.qrLogoSize) / 2; //logo相对于canvas居中定位
const h = that.qrLogoSize + 10; //圆角高 10为基数(logo四周白色背景为10/2)
const w = that.qrLogoSize + 10; //圆角宽
const x = logoPosition - 5;
const y = logoPosition - 5;
const 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();
ctx.restore(); //需要编辑canvas内容则需要写入
this.imgUrlToBase64(this.logoUrl).then(res => {
logoImg.src = res;
// logoImg.src = this.logoUrl + '?time=' + new Date().valueOf();
// logoImg.setAttribute('crossOrigin', 'anonymous');
// 绘制logo
logoImg.onload = () => {
ctx.drawImage(logoImg, logoPosition, logoPosition, that.qrLogoSize, that.qrLogoSize);
// 赋值链接
this.dataUrl = canvas.toDataURL();
};
});
};
},
imgUrlToBase64(url) {
return new Promise((resolve, reject) => {
if (!url) {
reject('请传入url内容');
}
if (/\.(png|jpe?g|gif|svg)(\?.*)?$/.test(url)) {
// 图片地址
const image = new Image();
// 设置跨域问题
image.setAttribute('crossOrigin', 'anonymous');
// 图片地址
image.src = url + '?time=' + new Date().valueOf();
image.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0, image.width, image.height);
// 获取图片后缀
const ext = url.substring(url.lastIndexOf('.') + 1).toLowerCase();
// 转base64
const dataUrl = canvas.toDataURL(`image/${ext}`);
resolve(dataUrl || '');
};
} else {
// 非图片地址
reject('非(png/jpe?g/gif/svg等)图片地址');
}
});
},
},
};
</script>

<style lang="scss" scoped>
.qrcode-box {
display: none;
img {
display: none;
}
}
.qrcode,
img {
width: 100%;
height: 100%;
}
</style>

使用

1
2
3
4
5
6
7
8
9
10
11
12
<af-qr-code
class="code-info"
:downloadTitle="downloadTitle"
ref="qrCodeUrl"
:url="shareUrl"
:isLogo="true"
:logoUrl="activityLogo"
/>
// 下载二维码
downloadFileFn() {
this.$refs.qrCodeUrl.downLoadImg();
},