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