mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-11-29 18:50:00 +08:00
chore: Watermark uses MutateObserver (#40081)
* chore: Watermark uses MutateObserver * chore: upgrade @rc-component/mutate-observer
This commit is contained in:
parent
52478c78d3
commit
26c3c326ad
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import Watermark from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { render, waitFor } from '../../../tests/utils';
|
||||
import { render, waitFor, waitFakeTimer } from '../../../tests/utils';
|
||||
|
||||
describe('Watermark', () => {
|
||||
mountTest(Watermark);
|
||||
@ -67,6 +67,7 @@ describe('Watermark', () => {
|
||||
it('MutationObserver should work properly', async () => {
|
||||
const { container } = render(<Watermark className="watermark" content="MutationObserver" />);
|
||||
const target = container.querySelector<HTMLDivElement>('.watermark div');
|
||||
await waitFakeTimer();
|
||||
target?.remove();
|
||||
await waitFor(() => expect(target).toBeTruthy());
|
||||
expect(container).toMatchSnapshot();
|
||||
@ -77,6 +78,7 @@ describe('Watermark', () => {
|
||||
<Watermark offset={[-200, -200]} className="watermark" content="MutationObserver" />,
|
||||
);
|
||||
const target = container.querySelector<HTMLDivElement>('.watermark div');
|
||||
await waitFakeTimer();
|
||||
target?.setAttribute('style', '');
|
||||
await waitFor(() => expect(target).toBeTruthy());
|
||||
expect(container).toMatchSnapshot();
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import useMutationObserver from './useMutationObserver';
|
||||
import { getStyleStr, getPixelRatio, rotateWatermark } from './utils';
|
||||
import MutateObserver from '@rc-component/mutate-observer';
|
||||
import { getStyleStr, getPixelRatio, rotateWatermark, reRendering } from './utils';
|
||||
|
||||
/**
|
||||
* Base size of the canvas, 1 for parallel layout and 2 for alternate layout
|
||||
@ -96,7 +96,7 @@ const Watermark: React.FC<WatermarkProps> = (props) => {
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const watermarkRef = useRef<HTMLDivElement>();
|
||||
const { createObserver, destroyObserver, reRendering } = useMutationObserver();
|
||||
const stopObservation = useRef(false);
|
||||
|
||||
const destroyWatermark = () => {
|
||||
if (watermarkRef.current) {
|
||||
@ -107,7 +107,7 @@ const Watermark: React.FC<WatermarkProps> = (props) => {
|
||||
|
||||
const appendWatermark = (base64Url: string, markWidth: number) => {
|
||||
if (containerRef.current && watermarkRef.current) {
|
||||
destroyObserver();
|
||||
stopObservation.current = true;
|
||||
watermarkRef.current.setAttribute(
|
||||
'style',
|
||||
getStyleStr({
|
||||
@ -117,14 +117,9 @@ const Watermark: React.FC<WatermarkProps> = (props) => {
|
||||
}),
|
||||
);
|
||||
containerRef.current?.append(watermarkRef.current);
|
||||
createObserver(containerRef.current, (mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (reRendering(mutation, watermarkRef.current)) {
|
||||
destroyWatermark();
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
renderWatermark();
|
||||
}
|
||||
});
|
||||
// Delayed execution
|
||||
setTimeout(() => {
|
||||
stopObservation.current = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -221,6 +216,18 @@ const Watermark: React.FC<WatermarkProps> = (props) => {
|
||||
}
|
||||
};
|
||||
|
||||
const onMutate = (mutations: MutationRecord[]) => {
|
||||
if (stopObservation.current) {
|
||||
return;
|
||||
}
|
||||
mutations.forEach((mutation) => {
|
||||
if (reRendering(mutation, watermarkRef.current)) {
|
||||
destroyWatermark();
|
||||
renderWatermark();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(renderWatermark, [
|
||||
rotate,
|
||||
zIndex,
|
||||
@ -240,9 +247,11 @@ const Watermark: React.FC<WatermarkProps> = (props) => {
|
||||
]);
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className={className} style={{ position: 'relative', ...style }}>
|
||||
{children}
|
||||
</div>
|
||||
<MutateObserver onMutate={onMutate}>
|
||||
<div ref={containerRef} className={className} style={{ position: 'relative', ...style }}>
|
||||
{children}
|
||||
</div>
|
||||
</MutateObserver>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,42 +0,0 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
export default function useMutationObserver() {
|
||||
const instance = useRef<MutationObserver>();
|
||||
|
||||
const destroyObserver = () => {
|
||||
if (instance.current) {
|
||||
instance.current.takeRecords();
|
||||
instance.current.disconnect();
|
||||
instance.current = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const createObserver = (target: Node, callback: MutationCallback) => {
|
||||
if (MutationObserver) {
|
||||
destroyObserver();
|
||||
instance.current = new MutationObserver(callback);
|
||||
instance.current.observe(target, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributeFilter: ['style', 'class'],
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => destroyObserver, []);
|
||||
|
||||
const reRendering = (mutation: MutationRecord, watermarkElement?: HTMLElement) => {
|
||||
let flag = false;
|
||||
// Whether to delete the watermark node
|
||||
if (mutation.removedNodes.length) {
|
||||
flag = Array.from(mutation.removedNodes).some((node) => node === watermarkElement);
|
||||
}
|
||||
// Whether the watermark dom property value has been modified
|
||||
if (mutation.type === 'attributes' && mutation.target === watermarkElement) {
|
||||
flag = true;
|
||||
}
|
||||
return flag;
|
||||
};
|
||||
|
||||
return { createObserver, destroyObserver, reRendering };
|
||||
}
|
@ -25,3 +25,17 @@ export function rotateWatermark(
|
||||
ctx.rotate((Math.PI / 180) * Number(rotate));
|
||||
ctx.translate(-rotateX, -rotateY);
|
||||
}
|
||||
|
||||
/** Whether to re-render the watermark */
|
||||
export const reRendering = (mutation: MutationRecord, watermarkElement?: HTMLElement) => {
|
||||
let flag = false;
|
||||
// Whether to delete the watermark node
|
||||
if (mutation.removedNodes.length) {
|
||||
flag = Array.from(mutation.removedNodes).some((node) => node === watermarkElement);
|
||||
}
|
||||
// Whether the watermark dom property value has been modified
|
||||
if (mutation.type === 'attributes' && mutation.target === watermarkElement) {
|
||||
flag = true;
|
||||
}
|
||||
return flag;
|
||||
};
|
||||
|
@ -113,6 +113,7 @@
|
||||
"@ant-design/react-slick": "~1.0.0",
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@ctrl/tinycolor": "^3.4.0",
|
||||
"@rc-component/mutate-observer": "^1.0.0",
|
||||
"@rc-component/tour": "~1.1.0",
|
||||
"classnames": "^2.2.6",
|
||||
"copy-to-clipboard": "^3.2.0",
|
||||
|
Loading…
Reference in New Issue
Block a user