Ver código fonte

feat(qrcode): custom drawing support (#580)

Netfan 4 anos atrás
pai
commit
2b76b88481

+ 11 - 7
src/components/Qrcode/src/index.vue

@@ -8,6 +8,7 @@
   import { toCanvas, QRCodeRenderersOptions, LogoType } from './qrcodePlus';
   import { toDataURL } from 'qrcode';
   import { downloadByUrl } from '/@/utils/file/download';
+  import { QrcodeDoneEventParams } from './types';
 
   export default defineComponent({
     name: 'QrCode',
@@ -38,10 +39,9 @@
         validator: (v: string) => ['canvas', 'img'].includes(v),
       },
     },
-    emits: { done: (url: string) => !!url, error: (error: any) => !!error },
+    emits: { done: (data: QrcodeDoneEventParams) => !!data, error: (error: any) => !!error },
     setup(props, { emit }) {
       const wrapRef = ref<HTMLCanvasElement | HTMLImageElement | null>(null);
-      const urlRef = ref<string>('');
       async function createQrcode() {
         try {
           const { tag, value, options = {}, width, logo } = props;
@@ -58,8 +58,7 @@
               content: renderValue,
               options: options || {},
             });
-            urlRef.value = url;
-            emit('done', url);
+            emit('done', { url, ctx: (wrapEl as HTMLCanvasElement).getContext('2d') });
             return;
           }
 
@@ -70,8 +69,7 @@
               ...options,
             });
             (unref(wrapRef) as HTMLImageElement).src = url;
-            urlRef.value = url;
-            emit('done', url);
+            emit('done', { url });
           }
         } catch (error) {
           emit('error', error);
@@ -81,7 +79,13 @@
        * file download
        */
       function download(fileName?: string) {
-        const url = unref(urlRef);
+        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,

+ 5 - 0
src/components/Qrcode/src/types.ts

@@ -31,3 +31,8 @@ export type ToCanvasFn = (options: RenderQrCodeParams) => Promise<unknown>;
 export interface QrCodeActionType {
   download: (fileName?: string) => void;
 }
+
+export interface QrcodeDoneEventParams {
+  url: string;
+  ctx?: CanvasRenderingContext2D | null;
+}

+ 33 - 0
src/views/demo/comp/qrcode/index.vue

@@ -58,6 +58,19 @@
       <CollapseContainer title="配置大小示例" class="text-center qrcode-demo-item">
         <QrCode :value="qrCodeUrl" :width="300" />
       </CollapseContainer>
+
+      <CollapseContainer title="扩展绘制示例" class="text-center qrcode-demo-item">
+        <QrCode
+          :value="qrCodeUrl"
+          :width="200"
+          :options="{ margin: 5 }"
+          ref="qrDiyRef"
+          :logo="LogoImg"
+          @done="onQrcodeDone"
+        />
+        <a-button class="mb-2" type="primary" @click="downloadDiy"> 下载 </a-button>
+        <div class="msg"> 要进行扩展绘制则不能将tag设为img </div>
+      </CollapseContainer>
     </div>
   </PageWrapper>
 </template>
@@ -73,16 +86,36 @@
     components: { CollapseContainer, QrCode, PageWrapper },
     setup() {
       const qrRef = ref<Nullable<QrCodeActionType>>(null);
+      const qrDiyRef = ref<Nullable<QrCodeActionType>>(null);
       function download() {
         const qrEl = unref(qrRef);
         if (!qrEl) return;
         qrEl.download('文件名');
       }
+      function downloadDiy() {
+        const qrEl = unref(qrDiyRef);
+        if (!qrEl) return;
+        qrEl.download('Qrcode');
+      }
+
+      function onQrcodeDone({ ctx }) {
+        if (ctx instanceof CanvasRenderingContext2D) {
+          // 额外绘制
+          ctx.fillStyle = 'black';
+          ctx.font = '16px "微软雅黑"';
+          ctx.textBaseline = 'bottom';
+          ctx.textAlign = 'center';
+          ctx.fillText('你帅你先扫', 100, 195, 200);
+        }
+      }
       return {
+        onQrcodeDone,
         qrCodeUrl,
         LogoImg,
         download,
+        downloadDiy,
         qrRef,
+        qrDiyRef,
       };
     },
   });