Ben Lin
2024-10-28 08abfcfea8247c394b2034cad59734846b403dd9
src/components/Qrcode/src/Qrcode.vue
@@ -3,110 +3,112 @@
    <component :is="tag" ref="wrapRef" />
  </div>
</template>
<script lang="ts">
  import { defineComponent, watch, PropType, ref, unref, onMounted } from 'vue';
<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 { downloadByUrl } from '@/utils/file/download';
  import { QrcodeDoneEventParams } from './typing';
  export default defineComponent({
    name: 'QrCode',
    props: {
      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),
      },
  defineOptions({ name: 'QrCode' });
  const props = defineProps({
    value: {
      type: [String, Array] as PropType<string | any[]>,
      default: null,
    },
    emits: { done: (data: QrcodeDoneEventParams) => !!data, error: (error: any) => !!error },
    setup(props, { emit }) {
      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,
        },
      );
      return { wrapRef, download };
    // 参数
    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>