Ver código fonte

fix(useWatermark): fix `func` call `createWatermark` call `clear` to resizeEvent removed (#901)

yanzhuang 3 anos atrás
pai
commit
a1d956d369
2 arquivos alterados com 71 adições e 21 exclusões
  1. 56 21
      src/hooks/web/useWatermark.ts
  2. 15 0
      src/utils/domUtils.ts

+ 56 - 21
src/hooks/web/useWatermark.ts

@@ -1,26 +1,36 @@
-import { getCurrentInstance, onBeforeUnmount, ref, Ref, unref } from 'vue';
+import { getCurrentInstance, onBeforeUnmount, ref, Ref, shallowRef, unref } from 'vue';
+import { useRafThrottle } from '/@/utils/domUtils';
+import { addResizeListener, removeResizeListener } from '/@/utils/event';
+import { isDef } from '/@/utils/is';
 
 const domSymbol = Symbol('watermark-dom');
 
 export function useWatermark(
   appendEl: Ref<HTMLElement | null> = ref(document.body) as Ref<HTMLElement>
 ) {
-  let func: Fn = () => {};
+  const func = useRafThrottle(function () {
+    const el = unref(appendEl);
+    if (!el) return;
+    const { clientHeight: height, clientWidth: width } = el;
+    updateWatermark({ height, width });
+  });
   const id = domSymbol.toString();
+  const watermarkEl = shallowRef<HTMLElement>();
+
   const clear = () => {
-    const domId = document.getElementById(id);
-    if (domId) {
-      const el = unref(appendEl);
-      el && el.removeChild(domId);
-    }
-    window.removeEventListener('resize', func);
+    const domId = unref(watermarkEl);
+    watermarkEl.value = undefined;
+    const el = unref(appendEl);
+    if (!el) return;
+    domId && el.removeChild(domId);
+    removeResizeListener(el, func);
   };
-  const createWatermark = (str: string) => {
-    clear();
 
+  function createBase64(str: string) {
     const can = document.createElement('canvas');
-    can.width = 300;
-    can.height = 240;
+    const width = 300;
+    const height = 240;
+    Object.assign(can, { width, height });
 
     const cans = can.getContext('2d');
     if (cans) {
@@ -29,30 +39,55 @@ export function useWatermark(
       cans.fillStyle = 'rgba(0, 0, 0, 0.15)';
       cans.textAlign = 'left';
       cans.textBaseline = 'middle';
-      cans.fillText(str, can.width / 20, can.height);
+      cans.fillText(str, width / 20, height);
     }
+    return can.toDataURL('image/png');
+  }
 
+  function updateWatermark(
+    options: {
+      width?: number;
+      height?: number;
+      str?: string;
+    } = {}
+  ) {
+    const el = unref(watermarkEl);
+    if (!el) return;
+    if (isDef(options.width)) {
+      el.style.width = `${options.width}px`;
+    }
+    if (isDef(options.height)) {
+      el.style.height = `${options.height}px`;
+    }
+    if (isDef(options.str)) {
+      el.style.background = `url(${createBase64(options.str)}) left top repeat`;
+    }
+  }
+
+  const createWatermark = (str: string) => {
+    if (unref(watermarkEl)) {
+      updateWatermark({ str });
+      return id;
+    }
     const div = document.createElement('div');
+    watermarkEl.value = div;
     div.id = id;
     div.style.pointerEvents = 'none';
     div.style.top = '0px';
     div.style.left = '0px';
     div.style.position = 'absolute';
     div.style.zIndex = '100000';
-    div.style.width = document.documentElement.clientWidth + 'px';
-    div.style.height = document.documentElement.clientHeight + 'px';
-    div.style.background = 'url(' + can.toDataURL('image/png') + ') left top repeat';
     const el = unref(appendEl);
-    el && el.appendChild(div);
+    if (!el) return id;
+    const { clientHeight: height, clientWidth: width } = el;
+    updateWatermark({ str, width, height });
+    el.appendChild(div);
     return id;
   };
 
   function setWatermark(str: string) {
     createWatermark(str);
-    func = () => {
-      createWatermark(str);
-    };
-    window.addEventListener('resize', func);
+    addResizeListener(document.documentElement, func);
     const instance = getCurrentInstance();
     if (instance) {
       onBeforeUnmount(() => {

+ 15 - 0
src/utils/domUtils.ts

@@ -1,3 +1,4 @@
+import type { FunctionArgs } from '@vueuse/core';
 import { upperFirst } from 'lodash-es';
 
 export interface ViewportOffsetResult {
@@ -163,3 +164,17 @@ export function once(el: HTMLElement, event: string, fn: EventListener): void {
   };
   on(el, event, listener);
 }
+
+export function useRafThrottle<T extends FunctionArgs>(fn: T): T {
+  let locked = false;
+  // @ts-ignore
+  return function (...args: any[]) {
+    if (locked) return;
+    locked = true;
+    window.requestAnimationFrame(() => {
+      // @ts-ignore
+      fn.apply(this, args);
+      locked = false;
+    });
+  };
+}