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
| <template>
| <div>
| <component :is="tag" ref="wrapRef" />
| </div>
| </template>
| <script lang="ts" setup>
| import { watch, PropType, ref, unref, onMounted } from 'vue';
| import { toCanvas, QRCodeRenderersOptions, LogoType } from './qrcodePlus';
| import { toDataURL } from 'qrcode';
| import { downloadByUrl } from '@/utils/file/download';
| import { QrcodeDoneEventParams } from './typing';
|
| defineOptions({ name: 'QrCode' });
|
| const props = defineProps({
| value: {
| type: [String, Array] as PropType<string | any[]>,
| default: null,
| },
| // 参数
| options: {
| type: Object as PropType<QRCodeRenderersOptions>,
| default: null,
| },
| // 宽度
| width: {
| type: Number as PropType<number>,
| default: 200,
| },
| // 中间logo图标
| logo: {
| type: [String, Object] as PropType<Partial<LogoType> | string>,
| default: '',
| },
| // img 不支持内嵌logo
| tag: {
| type: String as PropType<'canvas' | 'img'>,
| default: 'canvas',
| validator: (v: string) => ['canvas', 'img'].includes(v),
| },
| });
|
| const emit = defineEmits({
| done: (data: QrcodeDoneEventParams) => !!data,
| error: (error: any) => !!error,
| });
|
| const wrapRef = ref<HTMLCanvasElement | HTMLImageElement | null>(null);
| async function createQrcode() {
| try {
| const { tag, value, options = {}, width, logo } = props;
| const renderValue = String(value);
| const wrapEl = unref(wrapRef);
|
| if (!wrapEl) return;
|
| if (tag === 'canvas') {
| const url: string = await toCanvas({
| canvas: wrapEl,
| width,
| logo: logo as any,
| content: renderValue,
| options: options || {},
| });
| emit('done', { url, ctx: (wrapEl as HTMLCanvasElement).getContext('2d') });
| return;
| }
|
| if (tag === 'img') {
| const url = await toDataURL(renderValue, {
| errorCorrectionLevel: 'H',
| width,
| ...options,
| });
| (unref(wrapRef) as HTMLImageElement).src = url;
| emit('done', { url });
| }
| } catch (error) {
| emit('error', error);
| }
| }
| /**
| * file download
| */
| function download(fileName?: string) {
| let url = '';
| const wrapEl = unref(wrapRef);
| if (wrapEl instanceof HTMLCanvasElement) {
| url = wrapEl.toDataURL();
| } else if (wrapEl instanceof HTMLImageElement) {
| url = wrapEl.src;
| }
| if (!url) return;
| downloadByUrl({
| url,
| fileName,
| });
| }
|
| onMounted(createQrcode);
|
| // 监听参数变化重新生成二维码
| watch(
| props,
| () => {
| createQrcode();
| },
| {
| deep: true,
| },
| );
|
| defineExpose({ download });
| </script>
|
|