Commit a1d956d3697cd07e0ba8910768f2a73e55f18491
Committed by
GitHub
1 parent
35e13470
fix(useWatermark): fix `func` call `createWatermark` call `clear` to resizeEvent removed (#901)
Showing
2 changed files
with
71 additions
and
21 deletions
src/hooks/web/useWatermark.ts
1 | -import { getCurrentInstance, onBeforeUnmount, ref, Ref, unref } from 'vue'; | |
1 | +import { getCurrentInstance, onBeforeUnmount, ref, Ref, shallowRef, unref } from 'vue'; | |
2 | +import { useRafThrottle } from '/@/utils/domUtils'; | |
3 | +import { addResizeListener, removeResizeListener } from '/@/utils/event'; | |
4 | +import { isDef } from '/@/utils/is'; | |
2 | 5 | |
3 | 6 | const domSymbol = Symbol('watermark-dom'); |
4 | 7 | |
5 | 8 | export function useWatermark( |
6 | 9 | appendEl: Ref<HTMLElement | null> = ref(document.body) as Ref<HTMLElement> |
7 | 10 | ) { |
8 | - let func: Fn = () => {}; | |
11 | + const func = useRafThrottle(function () { | |
12 | + const el = unref(appendEl); | |
13 | + if (!el) return; | |
14 | + const { clientHeight: height, clientWidth: width } = el; | |
15 | + updateWatermark({ height, width }); | |
16 | + }); | |
9 | 17 | const id = domSymbol.toString(); |
18 | + const watermarkEl = shallowRef<HTMLElement>(); | |
19 | + | |
10 | 20 | const clear = () => { |
11 | - const domId = document.getElementById(id); | |
12 | - if (domId) { | |
13 | - const el = unref(appendEl); | |
14 | - el && el.removeChild(domId); | |
15 | - } | |
16 | - window.removeEventListener('resize', func); | |
21 | + const domId = unref(watermarkEl); | |
22 | + watermarkEl.value = undefined; | |
23 | + const el = unref(appendEl); | |
24 | + if (!el) return; | |
25 | + domId && el.removeChild(domId); | |
26 | + removeResizeListener(el, func); | |
17 | 27 | }; |
18 | - const createWatermark = (str: string) => { | |
19 | - clear(); | |
20 | 28 | |
29 | + function createBase64(str: string) { | |
21 | 30 | const can = document.createElement('canvas'); |
22 | - can.width = 300; | |
23 | - can.height = 240; | |
31 | + const width = 300; | |
32 | + const height = 240; | |
33 | + Object.assign(can, { width, height }); | |
24 | 34 | |
25 | 35 | const cans = can.getContext('2d'); |
26 | 36 | if (cans) { |
... | ... | @@ -29,30 +39,55 @@ export function useWatermark( |
29 | 39 | cans.fillStyle = 'rgba(0, 0, 0, 0.15)'; |
30 | 40 | cans.textAlign = 'left'; |
31 | 41 | cans.textBaseline = 'middle'; |
32 | - cans.fillText(str, can.width / 20, can.height); | |
42 | + cans.fillText(str, width / 20, height); | |
33 | 43 | } |
44 | + return can.toDataURL('image/png'); | |
45 | + } | |
34 | 46 | |
47 | + function updateWatermark( | |
48 | + options: { | |
49 | + width?: number; | |
50 | + height?: number; | |
51 | + str?: string; | |
52 | + } = {} | |
53 | + ) { | |
54 | + const el = unref(watermarkEl); | |
55 | + if (!el) return; | |
56 | + if (isDef(options.width)) { | |
57 | + el.style.width = `${options.width}px`; | |
58 | + } | |
59 | + if (isDef(options.height)) { | |
60 | + el.style.height = `${options.height}px`; | |
61 | + } | |
62 | + if (isDef(options.str)) { | |
63 | + el.style.background = `url(${createBase64(options.str)}) left top repeat`; | |
64 | + } | |
65 | + } | |
66 | + | |
67 | + const createWatermark = (str: string) => { | |
68 | + if (unref(watermarkEl)) { | |
69 | + updateWatermark({ str }); | |
70 | + return id; | |
71 | + } | |
35 | 72 | const div = document.createElement('div'); |
73 | + watermarkEl.value = div; | |
36 | 74 | div.id = id; |
37 | 75 | div.style.pointerEvents = 'none'; |
38 | 76 | div.style.top = '0px'; |
39 | 77 | div.style.left = '0px'; |
40 | 78 | div.style.position = 'absolute'; |
41 | 79 | div.style.zIndex = '100000'; |
42 | - div.style.width = document.documentElement.clientWidth + 'px'; | |
43 | - div.style.height = document.documentElement.clientHeight + 'px'; | |
44 | - div.style.background = 'url(' + can.toDataURL('image/png') + ') left top repeat'; | |
45 | 80 | const el = unref(appendEl); |
46 | - el && el.appendChild(div); | |
81 | + if (!el) return id; | |
82 | + const { clientHeight: height, clientWidth: width } = el; | |
83 | + updateWatermark({ str, width, height }); | |
84 | + el.appendChild(div); | |
47 | 85 | return id; |
48 | 86 | }; |
49 | 87 | |
50 | 88 | function setWatermark(str: string) { |
51 | 89 | createWatermark(str); |
52 | - func = () => { | |
53 | - createWatermark(str); | |
54 | - }; | |
55 | - window.addEventListener('resize', func); | |
90 | + addResizeListener(document.documentElement, func); | |
56 | 91 | const instance = getCurrentInstance(); |
57 | 92 | if (instance) { |
58 | 93 | onBeforeUnmount(() => { | ... | ... |
src/utils/domUtils.ts
1 | +import type { FunctionArgs } from '@vueuse/core'; | |
1 | 2 | import { upperFirst } from 'lodash-es'; |
2 | 3 | |
3 | 4 | export interface ViewportOffsetResult { |
... | ... | @@ -163,3 +164,17 @@ export function once(el: HTMLElement, event: string, fn: EventListener): void { |
163 | 164 | }; |
164 | 165 | on(el, event, listener); |
165 | 166 | } |
167 | + | |
168 | +export function useRafThrottle<T extends FunctionArgs>(fn: T): T { | |
169 | + let locked = false; | |
170 | + // @ts-ignore | |
171 | + return function (...args: any[]) { | |
172 | + if (locked) return; | |
173 | + locked = true; | |
174 | + window.requestAnimationFrame(() => { | |
175 | + // @ts-ignore | |
176 | + fn.apply(this, args); | |
177 | + locked = false; | |
178 | + }); | |
179 | + }; | |
180 | +} | ... | ... |