From 0218f72c5f8d0f54ee6e71a0134bbeff2fcaeb45 Mon Sep 17 00:00:00 2001 From: ezequielnick <107352853+ezequielnick@users.noreply.github.com> Date: Tue, 22 Apr 2025 23:19:41 +0800 Subject: [PATCH] fix: #587 --- src/renderer/src/pages/proxies.tsx | 79 ++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 16 deletions(-) diff --git a/src/renderer/src/pages/proxies.tsx b/src/renderer/src/pages/proxies.tsx index 007ca98..23a7fc1 100644 --- a/src/renderer/src/pages/proxies.tsx +++ b/src/renderer/src/pages/proxies.tsx @@ -34,6 +34,7 @@ const useProxyState = (groups: IMihomoMixedGroup[]): { setIsOpen: React.Dispatch>; scrollPosition: number; onScroll: (e: React.UIEvent) => void; + isManualScroll: React.RefObject; } => { const virtuosoRef = useRef(null) const [scrollPosition, setScrollPosition] = useState(0) @@ -78,25 +79,31 @@ const useProxyState = (groups: IMihomoMixedGroup[]): { if (savedPosition) { const position = parseInt(savedPosition) if (!isNaN(position) && position >= 0) { - // 只在首次加载或groups长度变化时恢复滚动位置 - if (lastGroupsLength.current === 0 || lastGroupsLength.current !== groups.length) { - lastGroupsLength.current = groups.length - const timer = setTimeout(() => { - virtuosoRef.current?.scrollTo({ - top: position, - behavior: 'auto' // 使用auto以避免平滑滚动引起的额外视觉效果 - }) - }, RENDER_DELAY) - return () => clearTimeout(timer) - } + // 记录当前组长度以便跟踪变化 + lastGroupsLength.current = groups.length + + // 设置标志位避免循环触发滚动 + isManualScroll.current = true; + + // 延迟一点时间确保DOM已更新 + const timer = setTimeout(() => { + virtuosoRef.current?.scrollTo({ + top: position, + behavior: 'auto' // 使用auto以避免平滑滚动引起的额外视觉效果 + }) + + // 延迟恢复标志位 + setTimeout(() => { + isManualScroll.current = false; + }, 200); + }, RENDER_DELAY) + return () => clearTimeout(timer) } } } catch (error) { console.error('Failed to restore scroll position:', error) } } - // 记录当前组长度以便跟踪变化 - lastGroupsLength.current = groups.length }, [groups]) // 数据刷新时保持滚动位置 @@ -138,7 +145,8 @@ const useProxyState = (groups: IMihomoMixedGroup[]): { saveScrollPosition(position) isManualScroll.current = false // 重置标记 }, SCROLL_DEBOUNCE_TIME) - }, [saveScrollPosition]) + }, [saveScrollPosition]), + isManualScroll } } @@ -157,7 +165,7 @@ const Proxies: React.FC = () => { } = appConfig || {} const [cols, setCols] = useState(1) - const { virtuosoRef, isOpen, setIsOpen, onScroll, scrollPosition } = useProxyState(groups) + const { virtuosoRef, isOpen, setIsOpen, onScroll, scrollPosition, isManualScroll } = useProxyState(groups) const [delaying, setDelaying] = useState(Array(groups.length).fill(false)) const [searchValue, setSearchValue] = useState(Array(groups.length).fill('')) const { groupCounts, allProxies } = useMemo(() => { @@ -192,6 +200,38 @@ const Proxies: React.FC = () => { return { groupCounts, allProxies } }, [groups, isOpen, proxyDisplayOrder, cols, searchValue]) + // 界面选项(如显示模式、排序方式)变化时恢复滚动位置 + useEffect(() => { + if (groups.length > 0) { + try { + const savedPosition = localStorage.getItem(SCROLL_POSITION_KEY) + if (savedPosition) { + const position = parseInt(savedPosition) + if (!isNaN(position) && position > 0) { + // 设置标志位避免循环触发滚动 + isManualScroll.current = true; + + // 延迟一点时间确保DOM已更新 + const timer = setTimeout(() => { + virtuosoRef.current?.scrollTo({ + top: position, + behavior: 'auto' + }) + + // 延迟恢复标志位 + setTimeout(() => { + isManualScroll.current = false; + }, 200); + }, 100) + return () => clearTimeout(timer) + } + } + } catch (error) { + console.error('Failed to restore scroll position after UI change:', error) + } + } + }, [proxyDisplayMode, proxyDisplayOrder]) + const onChangeProxy = useCallback(async (group: string, proxy: string): Promise => { // 保存当前滚动位置以便切换后恢复 const currentPosition = scrollPosition; @@ -202,12 +242,19 @@ const Proxies: React.FC = () => { } mutate() - // 使用单层requestAnimationFrame和更长的延迟来确保DOM更新完成 + // 设置标志位,表明这是程序控制的滚动,防止触发useEffect中的滚动 + isManualScroll.current = true; + setTimeout(() => { virtuosoRef.current?.scrollTo({ top: currentPosition, behavior: 'auto' // 使用auto避免出现平滑滚动导致的额外视觉抖动 }) + + // 延迟恢复标志位,确保滚动事件处理完成 + setTimeout(() => { + isManualScroll.current = false; + }, 200); }, 150) // 增加延迟让DOM有足够的时间更新 }, [autoCloseConnection, mutate, virtuosoRef, scrollPosition])