From f09930796bb67544fc9809bc0cefc0a929bdb69e Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Thu, 6 Apr 2023 20:18:29 +0800 Subject: [PATCH] perf: optimize the rendering animation and layer sequence of withKeepAliveOverlay --- .../KeepAliveOverlay/withKeepAliveOverlay.tsx | 33 ++++++++++++- .../src/routes/Main/Content/PageContent.tsx | 9 ++-- client/web/src/utils/dom-helper.ts | 49 +++++++++++++++++++ client/web/tailwind.config.js | 2 +- 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/client/web/src/components/KeepAliveOverlay/withKeepAliveOverlay.tsx b/client/web/src/components/KeepAliveOverlay/withKeepAliveOverlay.tsx index d1e7fe5b..eacf3bfd 100644 --- a/client/web/src/components/KeepAliveOverlay/withKeepAliveOverlay.tsx +++ b/client/web/src/components/KeepAliveOverlay/withKeepAliveOverlay.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useMemo, useRef } from 'react'; import { useKeepAliveStore } from './store'; import _omit from 'lodash/omit'; +import { createRAFLoop, getDOMParentPath } from '@/utils/dom-helper'; /** * 样式相关配置 @@ -49,6 +50,7 @@ export function withKeepAliveOverlay< return; } + // resize const resizeObserver = new ResizeObserver((entries) => { entries.forEach((entry) => { const { target } = entry; @@ -66,12 +68,41 @@ export function withKeepAliveOverlay< }); }); }); - resizeObserver.observe(containerRef.current); + // transition + const parentPath = getDOMParentPath(containerRef.current); + function update(e: TransitionEvent) { + if ( + containerRef.current && + parentPath.includes(e.target as HTMLElement) + ) { + // 父节点有触发 transition 事件,则更新容器节点大小 + const rect = containerRef.current.getBoundingClientRect(); + updateRect(cacheId, { + left: rect.left, + top: rect.top, + width: rect.width, + height: rect.height, + }); + } + } + + /** + * use raf to make sure smooth animation + */ + const { start: handleTransitionStart, end: handleTransitionEnd } = + createRAFLoop(update); + + window.addEventListener('transitionend', handleTransitionEnd); + window.addEventListener('transitionstart', handleTransitionStart); + return () => { if (containerRef.current) { resizeObserver.unobserve(containerRef.current); + + window.removeEventListener('transitionend', handleTransitionEnd); + window.removeEventListener('transitionstart', handleTransitionStart); } }; }, [cacheId]); diff --git a/client/web/src/routes/Main/Content/PageContent.tsx b/client/web/src/routes/Main/Content/PageContent.tsx index 4d28ac82..adfed0cb 100644 --- a/client/web/src/routes/Main/Content/PageContent.tsx +++ b/client/web/src/routes/Main/Content/PageContent.tsx @@ -105,7 +105,8 @@ export const PageContent: React.FC> = const contentMaskEl = showMask ? (
) : null; @@ -116,9 +117,11 @@ export const PageContent: React.FC> = {sidebarEl} + {contentMaskEl} +
> = 'overflow-hidden': showMask, })} > - {contentMaskEl} - {contentEl}
diff --git a/client/web/src/utils/dom-helper.ts b/client/web/src/utils/dom-helper.ts index a82ffb83..bdfa0a21 100644 --- a/client/web/src/utils/dom-helper.ts +++ b/client/web/src/utils/dom-helper.ts @@ -24,3 +24,52 @@ export function stopPropagation(e: React.BaseSyntheticEvent) { export function preventDefault(e: React.BaseSyntheticEvent) { e.preventDefault(); } + +/** + * 获取元素所有的DOM父节点列表 + */ +export function getDOMParentPath(el: HTMLElement): HTMLElement[] { + const path: HTMLElement[] = []; + let parent = el.parentElement; + while (parent) { + path.unshift(parent); + parent = parent.parentElement; + } + + return path; +} + +/** + * 创建一个RAF循环 + * @param loopFn 循环函数,在关闭前之前会执行最后一次 + * @returns + */ +export function createRAFLoop( + loopFn: (...args: T) => void +) { + let flag = false; + + const loop = (...args: T) => { + if (flag === false) { + return; + } + + loopFn(...args); + + requestAnimationFrame(() => { + loop(...args); + }); + }; + + return { + start: (...args: T) => { + flag = true; + loop(...args); + }, + end: () => { + requestAnimationFrame(() => { + flag = false; + }); + }, + }; +} diff --git a/client/web/tailwind.config.js b/client/web/tailwind.config.js index 3911b91f..d9e50c81 100644 --- a/client/web/tailwind.config.js +++ b/client/web/tailwind.config.js @@ -30,7 +30,7 @@ const tailchat = plugin(({ e, addUtilities }) => { right: 0, height: '1px', boxShadow: customTheme.boxShadow.elevationLow, - zIndex: 1, + // zIndex: 1, pointerEvents: 'none', }, },