mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-03 21:52:11 +08:00
refactor: proxy components
This commit is contained in:
@@ -46,6 +46,8 @@ interface ProxyChainItem {
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
const VirtuosoFooter = () => <div style={{ height: "8px" }} />;
|
||||
|
||||
export const ProxyGroups = (props: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { mode, isChainMode = false, chainConfigData } = props;
|
||||
@@ -61,23 +63,25 @@ export const ProxyGroups = (props: Props) => {
|
||||
|
||||
const { verge } = useVerge();
|
||||
const { proxies: proxiesData } = useAppData();
|
||||
const groups = proxiesData?.groups;
|
||||
const availableGroups = useMemo(() => groups ?? [], [groups]);
|
||||
|
||||
// 当链式代理模式且规则模式下,如果没有选择代理组,默认选择第一个
|
||||
useEffect(() => {
|
||||
if (
|
||||
isChainMode &&
|
||||
mode === "rule" &&
|
||||
!selectedGroup &&
|
||||
proxiesData?.groups?.length > 0
|
||||
) {
|
||||
setSelectedGroup(proxiesData.groups[0].name);
|
||||
const defaultRuleGroup = useMemo(() => {
|
||||
if (isChainMode && mode === "rule" && availableGroups.length > 0) {
|
||||
return availableGroups[0].name;
|
||||
}
|
||||
}, [isChainMode, mode, selectedGroup, proxiesData]);
|
||||
return null;
|
||||
}, [availableGroups, isChainMode, mode]);
|
||||
|
||||
const activeSelectedGroup = useMemo(
|
||||
() => selectedGroup ?? defaultRuleGroup,
|
||||
[selectedGroup, defaultRuleGroup],
|
||||
);
|
||||
|
||||
const { renderList, onProxies, onHeadState } = useRenderList(
|
||||
mode,
|
||||
isChainMode,
|
||||
selectedGroup,
|
||||
activeSelectedGroup,
|
||||
);
|
||||
|
||||
const getGroupHeadState = useCallback(
|
||||
@@ -112,6 +116,8 @@ export const ProxyGroups = (props: Props) => {
|
||||
useEffect(() => {
|
||||
if (renderList.length === 0) return;
|
||||
|
||||
let restoreTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
try {
|
||||
const savedPositions = localStorage.getItem("proxy-scroll-positions");
|
||||
if (savedPositions) {
|
||||
@@ -120,7 +126,7 @@ export const ProxyGroups = (props: Props) => {
|
||||
const savedPosition = positions[mode];
|
||||
|
||||
if (savedPosition !== undefined) {
|
||||
setTimeout(() => {
|
||||
restoreTimer = setTimeout(() => {
|
||||
virtuosoRef.current?.scrollTo({
|
||||
top: savedPosition,
|
||||
behavior: "auto",
|
||||
@@ -131,6 +137,12 @@ export const ProxyGroups = (props: Props) => {
|
||||
} catch (e) {
|
||||
console.error("Error restoring scroll position:", e);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (restoreTimer) {
|
||||
clearTimeout(restoreTimer);
|
||||
}
|
||||
};
|
||||
}, [mode, renderList.length]);
|
||||
|
||||
// 改为使用节流函数保存滚动位置
|
||||
@@ -150,25 +162,30 @@ export const ProxyGroups = (props: Props) => {
|
||||
);
|
||||
|
||||
// 使用改进的滚动处理
|
||||
const handleScroll = useCallback(
|
||||
throttle((e: any) => {
|
||||
const scrollTop = e.target.scrollTop;
|
||||
setShowScrollTop(scrollTop > 100);
|
||||
// 使用稳定的节流来保存位置,而不是setTimeout
|
||||
saveScrollPosition(scrollTop);
|
||||
}, 500), // 增加到500ms以确保平滑滚动
|
||||
const handleScroll = useMemo(
|
||||
() =>
|
||||
throttle((event: Event) => {
|
||||
const target = event.target as HTMLElement | null;
|
||||
const scrollTop = target?.scrollTop ?? 0;
|
||||
setShowScrollTop(scrollTop > 100);
|
||||
// 使用稳定的节流来保存位置,而不是setTimeout
|
||||
saveScrollPosition(scrollTop);
|
||||
}, 500), // 增加到500ms以确保平滑滚动
|
||||
[saveScrollPosition],
|
||||
);
|
||||
|
||||
// 添加和清理滚动事件监听器
|
||||
useEffect(() => {
|
||||
if (!scrollerRef.current) return;
|
||||
scrollerRef.current.addEventListener("scroll", handleScroll, {
|
||||
passive: true,
|
||||
});
|
||||
const node = scrollerRef.current;
|
||||
if (!node) return;
|
||||
|
||||
const listener = handleScroll as EventListener;
|
||||
const options: AddEventListenerOptions = { passive: true };
|
||||
|
||||
node.addEventListener("scroll", listener, options);
|
||||
|
||||
return () => {
|
||||
scrollerRef.current?.removeEventListener("scroll", handleScroll);
|
||||
node.removeEventListener("scroll", listener, options);
|
||||
};
|
||||
}, [handleScroll]);
|
||||
|
||||
@@ -186,18 +203,14 @@ export const ProxyGroups = (props: Props) => {
|
||||
setDuplicateWarning({ open: false, message: "" });
|
||||
}, []);
|
||||
|
||||
// 获取当前选中的代理组信息
|
||||
const getCurrentGroup = useCallback(() => {
|
||||
if (!selectedGroup || !proxiesData?.groups) return null;
|
||||
return proxiesData.groups.find(
|
||||
(group: any) => group.name === selectedGroup,
|
||||
const currentGroup = useMemo(() => {
|
||||
if (!activeSelectedGroup) return null;
|
||||
return (
|
||||
availableGroups.find(
|
||||
(group: any) => group.name === activeSelectedGroup,
|
||||
) ?? null
|
||||
);
|
||||
}, [selectedGroup, proxiesData]);
|
||||
|
||||
// 获取可用的代理组列表
|
||||
const getAvailableGroups = useCallback(() => {
|
||||
return proxiesData?.groups || [];
|
||||
}, [proxiesData]);
|
||||
}, [activeSelectedGroup, availableGroups]);
|
||||
|
||||
// 处理代理组选择菜单
|
||||
const handleGroupMenuOpen = (event: React.MouseEvent<HTMLElement>) => {
|
||||
@@ -220,9 +233,6 @@ export const ProxyGroups = (props: Props) => {
|
||||
}
|
||||
};
|
||||
|
||||
const currentGroup = getCurrentGroup();
|
||||
const availableGroups = getAvailableGroups();
|
||||
|
||||
const handleChangeProxy = useCallback(
|
||||
(group: IProxyGroupItem, proxy: IProxyItem) => {
|
||||
if (isChainMode) {
|
||||
@@ -472,7 +482,7 @@ export const ProxyGroups = (props: Props) => {
|
||||
scrollerRef.current = ref as Element;
|
||||
}}
|
||||
components={{
|
||||
Footer: () => <div style={{ height: "8px" }} />,
|
||||
Footer: VirtuosoFooter,
|
||||
}}
|
||||
initialScrollTop={scrollPositionRef.current[mode]}
|
||||
computeItemKey={(index) => renderList[index].key}
|
||||
@@ -498,7 +508,7 @@ export const ProxyGroups = (props: Props) => {
|
||||
onUpdateChain={setProxyChain}
|
||||
chainConfigData={chainConfigData}
|
||||
mode={mode}
|
||||
selectedGroup={selectedGroup}
|
||||
selectedGroup={activeSelectedGroup}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -530,11 +540,11 @@ export const ProxyGroups = (props: Props) => {
|
||||
},
|
||||
}}
|
||||
>
|
||||
{availableGroups.map((group: any, _index: number) => (
|
||||
{availableGroups.map((group: any) => (
|
||||
<MenuItem
|
||||
key={group.name}
|
||||
onClick={() => handleGroupSelect(group.name)}
|
||||
selected={selectedGroup === group.name}
|
||||
selected={activeSelectedGroup === group.name}
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
py: 1,
|
||||
@@ -591,7 +601,7 @@ export const ProxyGroups = (props: Props) => {
|
||||
scrollerRef.current = ref as Element;
|
||||
}}
|
||||
components={{
|
||||
Footer: () => <div style={{ height: "8px" }} />,
|
||||
Footer: VirtuosoFooter,
|
||||
}}
|
||||
// 添加平滑滚动设置
|
||||
initialScrollTop={scrollPositionRef.current[mode]}
|
||||
|
||||
Reference in New Issue
Block a user