Skip to content

Commit 0d82e61

Browse files
committed
optimize: 优化tab hook
1 parent 4e570ce commit 0d82e61

File tree

3 files changed

+176
-85
lines changed

3 files changed

+176
-85
lines changed

src/features/tab/GlobalTab.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ import { PageTab } from '@sa/materials';
22
import clsx from 'clsx';
33

44
import BetterScroll from '@/components/BetterScroll';
5-
import { useTheme } from '@/features/theme';
65
import { getFullContent, toggleFullContent } from '@/layouts/appStore';
76
import { isPC } from '@/utils/agent';
87

98
import { setRemoveCacheKey } from '../router/routeStore';
9+
import { useTheme, useThemeSettings } from '../theme';
1010

1111
import ContextMenu from './TabContextMenu';
1212
import TabReloadButton from './TabReloadButton';
13-
import { useTabActions } from './tabHooks';
13+
import { useTabActions, useTabManager } from './tabHooks';
1414
import { useTabScroll } from './useTabScroll';
1515

1616
const GlobalTab = () => {
@@ -20,10 +20,14 @@ const GlobalTab = () => {
2020

2121
const { darkMode } = useTheme();
2222

23-
const { activeTabId, dispatch, isTabRetain, navigate, removeTabById, tabs, themeSettings } = useTabActions();
23+
const themeSettings = useThemeSettings();
24+
25+
const { activeTabId, dispatch, isTabRetain, navigate, removeTabById, tabs } = useTabActions();
2426

2527
const { bsWrapper, setBsScroll, tabRef } = useTabScroll(activeTabId);
2628

29+
useTabManager();
30+
2731
const fullContent = useAppSelector(getFullContent);
2832

2933
const tabWrapperClass = themeSettings.tab.mode === 'chrome' ? 'items-end' : 'items-center gap-12px';

src/features/tab/TabContextMenu.tsx

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
import { useEmit } from '@sa/hooks';
2-
import { Dropdown } from 'antd';
31
import type { MenuProps } from 'antd';
42

5-
import { TabEvent } from './tabEnum';
3+
import { useTabController } from './tabHooks';
64

75
interface ContextMenuProps {
86
active: boolean;
@@ -39,6 +37,7 @@ function getMenu(options: DropdownOption[]) {
3937

4038
const ContextMenu = ({ children, disabledKeys = [], excludeKeys = [], tabId }: ContextMenuProps) => {
4139
const { t } = useTranslation();
40+
const { clearLeftTabs, clearRightTabs, closeAllTabs, closeCurrentTab, closeOtherTabs } = useTabController();
4241

4342
const options = () => {
4443
const opts: DropdownOption[] = [
@@ -79,25 +78,23 @@ const ContextMenu = ({ children, disabledKeys = [], excludeKeys = [], tabId }: C
7978
});
8079
};
8180

82-
const emit = useEmit();
83-
8481
const menu = getMenu(options());
8582

8683
const dropdownAction: Record<App.Global.DropdownKey, () => void> = {
8784
closeAll() {
88-
emit(TabEvent.UPDATE_TABS, TabEvent.CLOSE_ALL);
85+
closeAllTabs();
8986
},
9087
closeCurrent() {
91-
emit(TabEvent.UPDATE_TABS, TabEvent.CLOSE_CURRENT, tabId);
88+
closeCurrentTab(tabId);
9289
},
9390
closeLeft() {
94-
emit(TabEvent.UPDATE_TABS, TabEvent.CLEAR_LEFT_TABS, tabId);
91+
clearLeftTabs(tabId);
9592
},
9693
closeOther() {
97-
emit(TabEvent.UPDATE_TABS, TabEvent.CLOSE_OTHER, tabId);
94+
closeOtherTabs(tabId);
9895
},
9996
closeRight() {
100-
emit(TabEvent.UPDATE_TABS, TabEvent.CLEAR_RIGHT_TABS, tabId);
97+
clearRightTabs(tabId);
10198
}
10299
};
103100

@@ -106,12 +103,12 @@ const ContextMenu = ({ children, disabledKeys = [], excludeKeys = [], tabId }: C
106103
};
107104

108105
return (
109-
<Dropdown
106+
<ADropdown
110107
menu={{ items: menu, onClick: handleClick }}
111108
trigger={['contextMenu']}
112109
>
113110
{children}
114-
</Dropdown>
111+
</ADropdown>
115112
);
116113
};
117114

src/features/tab/tabHooks.ts

Lines changed: 160 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { useOn } from '@sa/hooks';
1+
import { useEmit, useOn } from '@sa/hooks';
22

33
import { useRoute, useRouter } from '@/features/router';
44
import {
55
addTab,
6+
changeTabLabel,
67
selectActiveTabId,
78
selectTabs,
89
setActiveFirstLevelMenuKey,
@@ -17,34 +18,36 @@ import { useThemeSettings } from '../theme';
1718
import { filterTabsById, filterTabsByIds, getFixedTabs, getTabByRoute, isTabInTabs } from './shared';
1819
import { TabEvent } from './tabEnum';
1920

20-
export function useTabActions() {
21+
export function useUpdateTabs() {
2122
const dispatch = useAppDispatch();
2223

23-
const tabs = useAppSelector(selectTabs);
24+
/**
25+
* 更新标签页
26+
*
27+
* @param newTabs
28+
*/
29+
function updateTabs(newTabs: App.Global.Tab[]) {
30+
dispatch(setTabs(newTabs));
31+
}
2432

25-
const _route = useRoute();
33+
return updateTabs;
34+
}
2635

27-
const isInit = useRef(false);
36+
export function useTabActions() {
37+
const dispatch = useAppDispatch();
38+
39+
const tabs = useAppSelector(selectTabs);
2840

2941
const _fixedTabs = getFixedTabs(tabs);
3042

31-
const _tabIds = tabs.map(tab => tab.id);
43+
const updateTabs = useUpdateTabs();
3244

33-
const themeSettings = useThemeSettings();
45+
const _tabIds = tabs.map(tab => tab.id);
3446

3547
const { navigate } = useRouter();
3648

3749
const activeTabId = useAppSelector(selectActiveTabId);
3850

39-
/**
40-
* 更新标签页
41-
*
42-
* @param newTabs
43-
*/
44-
function updateTabs(newTabs: App.Global.Tab[]) {
45-
dispatch(setTabs(newTabs));
46-
}
47-
4851
/**
4952
* 切换激活的标签页
5053
*
@@ -127,46 +130,6 @@ export function useTabActions() {
127130
_clearTabs(excludes);
128131
}
129132

130-
function _initTabs() {
131-
const storageTabs = localStg.get('globalTabs');
132-
133-
if (themeSettings.tab.cache && storageTabs) {
134-
// const tabs = extractTabsByAllRoutes(router.getAllRouteNames(), storageTabs);
135-
// dispatch(setTabs(tabs));
136-
updateTabs(storageTabs);
137-
return storageTabs;
138-
}
139-
140-
return [];
141-
}
142-
143-
function _cacheTabs() {
144-
if (!themeSettings.tab.cache) return;
145-
146-
localStg.set('globalTabs', tabs);
147-
}
148-
149-
function _addTab(route: Router.Route) {
150-
const tab = getTabByRoute(route);
151-
152-
if (!isInit.current) {
153-
isInit.current = true;
154-
155-
const initTabs = _initTabs();
156-
157-
if (!initTabs || initTabs.length === 0 || (initTabs.length > 0 && !isTabInTabs(tab.id, initTabs))) {
158-
dispatch(addTab(tab));
159-
}
160-
} else if (!isTabInTabs(tab.id, tabs)) {
161-
dispatch(addTab(tab));
162-
}
163-
164-
dispatch(setActiveTabId(tab.id));
165-
166-
const firstLevelRouteName = getActiveFirstLevelMenuKey(route);
167-
dispatch(setActiveFirstLevelMenuKey(firstLevelRouteName));
168-
}
169-
170133
/**
171134
* 删除标签页
172135
*
@@ -192,6 +155,10 @@ export function useTabActions() {
192155
}
193156
}
194157

158+
function removeActiveTab() {
159+
removeTabById(activeTabId);
160+
}
161+
195162
/**
196163
* 判断标签页是否保留
197164
*
@@ -202,18 +169,6 @@ export function useTabActions() {
202169
return _fixedTabs.some(tab => tab.id === tabId);
203170
}
204171

205-
useEffect(() => {
206-
_addTab(_route);
207-
}, [_route.fullPath]);
208-
209-
useEventListener(
210-
'beforeunload',
211-
() => {
212-
_cacheTabs();
213-
},
214-
{ target: window }
215-
);
216-
217172
useOn(TabEvent.UPDATE_TABS, (eventName: TabEvent, id: string) => {
218173
// 清除左侧标签页
219174
if (eventName === TabEvent.CLEAR_LEFT_TABS) return _clearLeftTabs(id);
@@ -236,8 +191,143 @@ export function useTabActions() {
236191
dispatch,
237192
isTabRetain,
238193
navigate,
194+
removeActiveTab,
239195
removeTabById,
240-
tabs,
241-
themeSettings
196+
tabs
197+
};
198+
}
199+
200+
export function useTabController() {
201+
const emit = useEmit();
202+
203+
function _operateTab(eventName: TabEvent, id?: string) {
204+
emit(TabEvent.UPDATE_TABS, eventName, id);
205+
}
206+
207+
function clearLeftTabs(id: string) {
208+
_operateTab(TabEvent.CLEAR_LEFT_TABS, id);
209+
}
210+
211+
function clearRightTabs(id: string) {
212+
_operateTab(TabEvent.CLEAR_RIGHT_TABS, id);
213+
}
214+
215+
function closeCurrentTab(id: string) {
216+
_operateTab(TabEvent.CLOSE_CURRENT, id);
217+
}
218+
219+
function closeOtherTabs(id: string) {
220+
_operateTab(TabEvent.CLOSE_OTHER, id);
221+
}
222+
223+
function closeAllTabs() {
224+
_operateTab(TabEvent.CLOSE_ALL);
225+
}
226+
227+
return {
228+
clearLeftTabs,
229+
clearRightTabs,
230+
closeAllTabs,
231+
closeCurrentTab,
232+
closeOtherTabs
233+
};
234+
}
235+
236+
export function useTabManager() {
237+
const isInit = useRef(false);
238+
239+
const themeSettings = useThemeSettings();
240+
241+
const tabs = useAppSelector(selectTabs);
242+
243+
const dispatch = useAppDispatch();
244+
245+
const _route = useRoute();
246+
247+
const updateTabs = useUpdateTabs();
248+
249+
function _initTabs() {
250+
const storageTabs = localStg.get('globalTabs');
251+
252+
if (themeSettings.tab.cache && storageTabs) {
253+
// const tabs = extractTabsByAllRoutes(router.getAllRouteNames(), storageTabs);
254+
// dispatch(setTabs(tabs));
255+
updateTabs(storageTabs);
256+
return storageTabs;
257+
}
258+
259+
return [];
260+
}
261+
262+
function _cacheTabs() {
263+
if (!themeSettings.tab.cache) return;
264+
265+
localStg.set('globalTabs', tabs);
266+
}
267+
268+
function _addTab(route: Router.Route) {
269+
const tab = getTabByRoute(route);
270+
271+
if (!isInit.current) {
272+
isInit.current = true;
273+
274+
const initTabs = _initTabs();
275+
276+
if (!initTabs || initTabs.length === 0 || (initTabs.length > 0 && !isTabInTabs(tab.id, initTabs))) {
277+
dispatch(addTab(tab));
278+
}
279+
} else if (!isTabInTabs(tab.id, tabs)) {
280+
dispatch(addTab(tab));
281+
}
282+
283+
dispatch(setActiveTabId(tab.id));
284+
285+
const firstLevelRouteName = getActiveFirstLevelMenuKey(route);
286+
dispatch(setActiveFirstLevelMenuKey(firstLevelRouteName));
287+
}
288+
289+
useEffect(() => {
290+
_addTab(_route);
291+
}, [_route.fullPath]);
292+
293+
useEventListener(
294+
'beforeunload',
295+
() => {
296+
_cacheTabs();
297+
},
298+
{ target: window }
299+
);
300+
}
301+
302+
export function useTabLabel() {
303+
const dispatch = useAppDispatch();
304+
305+
const activeTabId = useAppSelector(selectActiveTabId);
306+
307+
const tabs = useAppSelector(selectTabs);
308+
309+
function setTabLabel(label: string, tabId?: string) {
310+
const id = tabId || activeTabId;
311+
312+
const tab = tabs.findIndex(item => item.id === id);
313+
314+
if (tab < 0) return;
315+
316+
dispatch(changeTabLabel({ index: tab, label }));
317+
}
318+
319+
function resetTabLabel(tabId?: string) {
320+
const id = tabId || activeTabId;
321+
322+
const tab = tabs.findIndex(item => item.id === id);
323+
324+
if (tab < 0) return;
325+
326+
dispatch(changeTabLabel({ index: tab }));
327+
}
328+
329+
return {
330+
resetTabLabel,
331+
setTabLabel
242332
};
243333
}

0 commit comments

Comments
 (0)