vue-stack-tabs 0.1.51 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +717 -3
- package/dist/index.d.ts +3 -0
- package/dist/src/lib/StackTabs.vue.d.ts +33 -161
- package/dist/src/lib/components/ContextMenu/ContextMenuItem.vue.d.ts +6 -6
- package/dist/src/lib/components/ContextMenu/index.vue.d.ts +14 -14
- package/dist/src/lib/components/PageLoading.vue.d.ts +5 -5
- package/dist/src/lib/components/TabHeader/TabHeaderButton.vue.d.ts +24 -15
- package/dist/src/lib/components/TabHeader/TabHeaderItem.vue.d.ts +10 -8
- package/dist/src/lib/components/TabHeader/TabHeaderScroll.vue.d.ts +31 -13
- package/dist/src/lib/components/TabHeader/index.vue.d.ts +172 -20
- package/dist/src/lib/hooks/tabPanel/evict.d.ts +24 -0
- package/dist/src/lib/hooks/tabPanel/evict.spec.d.ts +1 -0
- package/dist/src/lib/hooks/tabPanel/scroll.d.ts +8 -0
- package/dist/src/lib/hooks/tabPanel/session.d.ts +9 -0
- package/dist/src/lib/hooks/tabPanel/state.d.ts +77 -0
- package/dist/src/lib/hooks/useContextMenu.d.ts +6 -1
- package/dist/src/lib/hooks/useTabActions.d.ts +68 -0
- package/dist/src/lib/hooks/{useTabMitt.d.ts → useTabEventBus.d.ts} +4 -3
- package/dist/src/lib/hooks/useTabLoading.d.ts +6 -0
- package/dist/src/lib/hooks/{useTabpanel.d.ts → useTabPanel.d.ts} +20 -14
- package/dist/src/lib/hooks/useTabPanel.spec.d.ts +1 -0
- package/dist/src/lib/hooks/useTabRouter.d.ts +14 -5
- package/dist/src/lib/i18n/index.d.ts +1 -1
- package/dist/src/lib/i18n/lang/en.d.ts +1 -0
- package/dist/src/lib/i18n/lang/zh-CN.d.ts +1 -0
- package/dist/src/lib/index.d.ts +5 -4
- package/dist/src/lib/model/TabModel.d.ts +20 -3
- package/dist/src/lib/model/TabModel.spec.d.ts +1 -0
- package/dist/src/lib/utils/iframeBridge.d.ts +31 -0
- package/dist/src/lib/utils/iframeBridge.spec.d.ts +1 -0
- package/dist/src/lib/utils/scrollUtils.d.ts +28 -0
- package/dist/src/lib/utils/tabInfoEncoder.d.ts +19 -0
- package/dist/src/lib/utils/tabInfoEncoder.spec.d.ts +1 -0
- package/dist/src/lib/utils/urlParser.d.ts +19 -0
- package/dist/src/lib/utils/urlParser.spec.d.ts +1 -0
- package/dist/src/lib/versionLogger.d.ts +2 -0
- package/dist/style.css +1 -1
- package/dist/vue-stack-tabs.css +1 -0
- package/dist/vue-stack-tabs.es.js +1795 -1679
- package/dist/vue-stack-tabs.umd.js +1 -5
- package/package.json +76 -39
- package/src/lib/StackTabs.vue +222 -47
- package/src/lib/assets/image/open.svg +1 -0
- package/src/lib/assets/style/common/var.scss +1 -1
- package/src/lib/assets/style/icon.scss +6 -0
- package/src/lib/assets/style/stackTab.scss +44 -3
- package/src/lib/assets/style/transition.scss +63 -62
- package/src/lib/components/ContextMenu/ContextMenuItem.vue +7 -0
- package/src/lib/components/ContextMenu/index.vue +50 -38
- package/src/lib/components/PageLoading.vue +30 -10
- package/src/lib/components/TabHeader/TabHeaderButton.vue +12 -3
- package/src/lib/components/TabHeader/TabHeaderItem.vue +31 -27
- package/src/lib/components/TabHeader/TabHeaderScroll.vue +83 -77
- package/src/lib/components/TabHeader/index.vue +45 -40
- package/src/lib/hooks/tabPanel/evict.spec.ts +85 -0
- package/src/lib/hooks/tabPanel/evict.ts +57 -0
- package/src/lib/hooks/tabPanel/scroll.ts +52 -0
- package/src/lib/hooks/tabPanel/session.ts +33 -0
- package/src/lib/hooks/tabPanel/state.ts +52 -0
- package/src/lib/hooks/useContextMenu.ts +22 -20
- package/src/lib/hooks/useTabActions.ts +148 -0
- package/src/lib/hooks/useTabEventBus.ts +31 -0
- package/src/lib/hooks/useTabLoading.ts +12 -4
- package/src/lib/hooks/useTabPanel.spec.ts +34 -0
- package/src/lib/hooks/useTabPanel.tsx +546 -0
- package/src/lib/hooks/useTabRouter.ts +114 -103
- package/src/lib/i18n/index.ts +14 -18
- package/src/lib/i18n/lang/en.ts +2 -1
- package/src/lib/i18n/lang/zh-CN.ts +2 -1
- package/src/lib/iframe.vue +6 -0
- package/src/lib/index.ts +27 -8
- package/src/lib/model/TabModel.spec.ts +40 -0
- package/src/lib/model/TabModel.ts +22 -9
- package/src/lib/nuxt/module.d.ts +19 -0
- package/src/lib/nuxt/module.ts +34 -0
- package/src/lib/nuxt/runtime/plugin.client.ts +11 -0
- package/src/lib/utils/iframeBridge.spec.ts +37 -0
- package/src/lib/utils/iframeBridge.ts +52 -0
- package/src/lib/utils/{TabScrollHelper.ts → scrollUtils.ts} +23 -29
- package/src/lib/utils/tabInfoEncoder.spec.ts +42 -0
- package/src/lib/utils/tabInfoEncoder.ts +65 -0
- package/src/lib/utils/urlParser.spec.ts +45 -0
- package/src/lib/utils/urlParser.ts +42 -0
- package/src/lib/{banner.ts → versionLogger.ts} +4 -5
- package/dist/src/lib/banner.d.ts +0 -2
- package/dist/src/lib/hooks/useStackTab.d.ts +0 -11
- package/dist/src/lib/utils/TabIdHelper.d.ts +0 -11
- package/dist/src/lib/utils/TabScrollHelper.d.ts +0 -33
- package/dist/src/lib/utils/UriHelper.d.ts +0 -4
- package/src/lib/hooks/useStackTab.ts +0 -119
- package/src/lib/hooks/useTabMitt.ts +0 -30
- package/src/lib/hooks/useTabpanel.tsx +0 -708
- package/src/lib/utils/TabIdHelper.ts +0 -70
- package/src/lib/utils/UriHelper.ts +0 -22
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ITabItem } from '../../model/TabModel';
|
|
2
|
+
/** 获取 sessionStorage 的 key */
|
|
3
|
+
export declare const getSessionKey: () => string;
|
|
4
|
+
/** 将当前激活的标签保存到 sessionStorage */
|
|
5
|
+
export declare const saveActiveTabToSession: (tab: ITabItem) => void;
|
|
6
|
+
/** 清除 sessionStorage 中的激活标签 */
|
|
7
|
+
export declare const clearSession: () => void;
|
|
8
|
+
/** 从 sessionStorage 解析恢复的标签(含 Stack 反序列化) */
|
|
9
|
+
export declare const restoreTabFromSession: (storedJson: string | null) => ITabItem | null;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { ITabItem } from '../../model/TabModel';
|
|
2
|
+
/** 当前打开的标签列表(含每个标签的页面栈) */
|
|
3
|
+
export declare const tabs: import('vue').Ref<{
|
|
4
|
+
id: string;
|
|
5
|
+
closable: boolean;
|
|
6
|
+
refreshable: boolean;
|
|
7
|
+
iframe: boolean;
|
|
8
|
+
iframeRefreshMode?: import('../..').IframeRefreshMode | undefined;
|
|
9
|
+
url?: string | undefined;
|
|
10
|
+
active: boolean;
|
|
11
|
+
pages: {
|
|
12
|
+
push: (element: import('../..').ITabPage) => void;
|
|
13
|
+
pop: () => import('../..').ITabPage | undefined;
|
|
14
|
+
peek: () => import('../..').ITabPage | undefined;
|
|
15
|
+
isEmpty: () => boolean;
|
|
16
|
+
size: () => number;
|
|
17
|
+
clear: () => void;
|
|
18
|
+
list: () => import('../..').ITabPage[];
|
|
19
|
+
toString: () => string;
|
|
20
|
+
toJSON: () => import('../..').ITabPage[];
|
|
21
|
+
};
|
|
22
|
+
title: string;
|
|
23
|
+
}[], ITabItem[] | {
|
|
24
|
+
id: string;
|
|
25
|
+
closable: boolean;
|
|
26
|
+
refreshable: boolean;
|
|
27
|
+
iframe: boolean;
|
|
28
|
+
iframeRefreshMode?: import('../..').IframeRefreshMode | undefined;
|
|
29
|
+
url?: string | undefined;
|
|
30
|
+
active: boolean;
|
|
31
|
+
pages: {
|
|
32
|
+
push: (element: import('../..').ITabPage) => void;
|
|
33
|
+
pop: () => import('../..').ITabPage | undefined;
|
|
34
|
+
peek: () => import('../..').ITabPage | undefined;
|
|
35
|
+
isEmpty: () => boolean;
|
|
36
|
+
size: () => number;
|
|
37
|
+
clear: () => void;
|
|
38
|
+
list: () => import('../..').ITabPage[];
|
|
39
|
+
toString: () => string;
|
|
40
|
+
toJSON: () => import('../..').ITabPage[];
|
|
41
|
+
};
|
|
42
|
+
title: string;
|
|
43
|
+
}[]>;
|
|
44
|
+
/** 初始化时传入的默认标签(用于对比 session 恢复) */
|
|
45
|
+
export declare const defaultTabs: ITabItem[];
|
|
46
|
+
/** keep-alive include 数组,与 Vue 的 keep-alive :include 绑定 */
|
|
47
|
+
export declare const caches: import('vue').Ref<string[], string[]>;
|
|
48
|
+
/** 页面缓存 ID -> 包装后的 DefineComponent */
|
|
49
|
+
export declare const components: Map<string, import('vue').DefineComponent<{}, {}, {}, import('vue').ComputedOptions, import('vue').MethodOptions, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{}>>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>>;
|
|
50
|
+
/** 待驱逐的页面缓存 ID 集合 */
|
|
51
|
+
export declare const cacheIdsToEvict: Set<string>;
|
|
52
|
+
/** 待驱逐的标签 ID 集合 */
|
|
53
|
+
export declare const tabIdsToEvict: Set<string>;
|
|
54
|
+
/** 刷新计数器,变更时触发 component :key 变化 */
|
|
55
|
+
export declare const refreshKey: import('vue').Ref<number, number>;
|
|
56
|
+
/** 刷新时临时加入 keep-alive exclude 的缓存 ID */
|
|
57
|
+
export declare const excludedCacheIdsForRefresh: import('vue').Ref<string[], string[]>;
|
|
58
|
+
/** pageCacheId -> Map<selector, { top, left }> 滚动位置存储 */
|
|
59
|
+
export declare const scrollPositionsByPageId: Map<string, Map<string, {
|
|
60
|
+
top: number;
|
|
61
|
+
left: number;
|
|
62
|
+
}>>;
|
|
63
|
+
/** 是否已完成初始化 */
|
|
64
|
+
export declare const isInitialized: import('vue').Ref<boolean, boolean>;
|
|
65
|
+
/** sessionStorage 中存储当前激活标签的 key 前缀 */
|
|
66
|
+
export declare const SESSION_TAB_NAME = "stacktab-active-tab";
|
|
67
|
+
/** iframe 标签 tabId -> 刷新序号,变更时触发 iframe 重载 */
|
|
68
|
+
export declare const iframeRefreshKeys: import('vue').Ref<Record<string, number>, Record<string, number>>;
|
|
69
|
+
/** 最大标签数量,0 表示不限制 */
|
|
70
|
+
export declare let maxTabCount: number;
|
|
71
|
+
/** 是否使用页面级滚动 */
|
|
72
|
+
export declare let useGlobalScroll: boolean;
|
|
73
|
+
/** sessionStorage key 前缀 */
|
|
74
|
+
export declare let sessionPrefix: string;
|
|
75
|
+
export declare const setMaxTabCount: (n: number) => void;
|
|
76
|
+
export declare const setUseGlobalScroll: (v: boolean) => void;
|
|
77
|
+
export declare const setSessionPrefix: (p: string) => void;
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { ITabItem } from '../model/TabModel';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* useContextMenu - 标签右键菜单 Hook
|
|
4
|
+
*
|
|
5
|
+
* 职责:管理右键菜单的显示/隐藏、定位,点击菜单外区域关闭
|
|
6
|
+
* 使用:TabHeader 中右键标签时调用 showContextMenu
|
|
7
|
+
*/
|
|
3
8
|
declare const _default: () => {
|
|
4
9
|
shown: import('vue').Ref<boolean, boolean>;
|
|
5
10
|
contextMenuData: {
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { throttle } from 'throttle-debounce';
|
|
2
|
+
import { ITabData, IframeRefreshMode } from '../model/TabModel';
|
|
3
|
+
/**
|
|
4
|
+
* useTabActions - 标签操作对外 Hook
|
|
5
|
+
*
|
|
6
|
+
* 职责:提供打开、关闭、刷新标签等用户级 API,内部委托 useTabPanel 执行
|
|
7
|
+
* 使用范围:业务代码、ContextMenu、TabHeader 等
|
|
8
|
+
*
|
|
9
|
+
* 主要 API:
|
|
10
|
+
* - openTab(tab, renew?) 打开或续签标签
|
|
11
|
+
* - closeTab(id) / closeAllTabs() 关闭标签
|
|
12
|
+
* - refreshTab(id) / refreshAllTabs() 刷新
|
|
13
|
+
* - activeTab(id, isRoute?) 激活标签
|
|
14
|
+
* - reset() 重置(关闭所有)
|
|
15
|
+
*/
|
|
16
|
+
export default function useTabActions(): {
|
|
17
|
+
openTab: throttle<(tab: ITabData, renew?: any) => Promise<string | undefined>>;
|
|
18
|
+
closeTab: (id: string) => string;
|
|
19
|
+
closeAllTabs: () => void;
|
|
20
|
+
refreshTab: (id: string) => void;
|
|
21
|
+
refreshAllTabs: () => void;
|
|
22
|
+
activeTab: (id: string, route?: boolean) => void;
|
|
23
|
+
reset: () => void;
|
|
24
|
+
tabs: import('vue').Ref<{
|
|
25
|
+
id: string;
|
|
26
|
+
closable: boolean;
|
|
27
|
+
refreshable: boolean;
|
|
28
|
+
iframe: boolean;
|
|
29
|
+
iframeRefreshMode?: IframeRefreshMode | undefined;
|
|
30
|
+
url?: string | undefined;
|
|
31
|
+
active: boolean;
|
|
32
|
+
pages: {
|
|
33
|
+
push: (element: import('..').ITabPage) => void;
|
|
34
|
+
pop: () => import('..').ITabPage | undefined;
|
|
35
|
+
peek: () => import('..').ITabPage | undefined;
|
|
36
|
+
isEmpty: () => boolean;
|
|
37
|
+
size: () => number;
|
|
38
|
+
clear: () => void;
|
|
39
|
+
list: () => import('..').ITabPage[];
|
|
40
|
+
toString: () => string;
|
|
41
|
+
toJSON: () => import('..').ITabPage[];
|
|
42
|
+
};
|
|
43
|
+
title: string;
|
|
44
|
+
}[], import('..').ITabItem[] | {
|
|
45
|
+
id: string;
|
|
46
|
+
closable: boolean;
|
|
47
|
+
refreshable: boolean;
|
|
48
|
+
iframe: boolean;
|
|
49
|
+
iframeRefreshMode?: IframeRefreshMode | undefined;
|
|
50
|
+
url?: string | undefined;
|
|
51
|
+
active: boolean;
|
|
52
|
+
pages: {
|
|
53
|
+
push: (element: import('..').ITabPage) => void;
|
|
54
|
+
pop: () => import('..').ITabPage | undefined;
|
|
55
|
+
peek: () => import('..').ITabPage | undefined;
|
|
56
|
+
isEmpty: () => boolean;
|
|
57
|
+
size: () => number;
|
|
58
|
+
clear: () => void;
|
|
59
|
+
list: () => import('..').ITabPage[];
|
|
60
|
+
toString: () => string;
|
|
61
|
+
toJSON: () => import('..').ITabPage[];
|
|
62
|
+
};
|
|
63
|
+
title: string;
|
|
64
|
+
}[]>;
|
|
65
|
+
setIFramePath: (path: string) => void;
|
|
66
|
+
getWrapper: () => Element | undefined;
|
|
67
|
+
openInNewWindow: (id: string) => void;
|
|
68
|
+
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Emitter, EventType } from 'mitt';
|
|
2
2
|
import { App } from 'vue';
|
|
3
|
-
|
|
4
3
|
declare module '@vue/runtime-core' {
|
|
5
4
|
interface ComponentCustomProperties {
|
|
6
5
|
$layerEmitter: Emitter<Record<EventType, unknown>>;
|
|
@@ -9,8 +8,10 @@ declare module '@vue/runtime-core' {
|
|
|
9
8
|
declare const plugin: {
|
|
10
9
|
install(app: App): void;
|
|
11
10
|
};
|
|
12
|
-
|
|
13
|
-
export declare
|
|
11
|
+
/** 获取标签事件总线,用于组件间通信 */
|
|
12
|
+
export declare const useTabEmitter: <T extends Record<EventType, unknown>>() => Emitter<T>;
|
|
13
|
+
/** 标签相关事件类型 */
|
|
14
|
+
export declare enum TabEventType {
|
|
14
15
|
PAGE_LOADING = "PAGE_LOADING",
|
|
15
16
|
TAB_ACTIVE = "TAB_ACTIVE"
|
|
16
17
|
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { ITabData, ITabItem, ITabPage } from '../model/TabModel';
|
|
2
2
|
import { DefineComponent, VNode } from 'vue';
|
|
3
3
|
import { RouteLocationNormalizedLoaded } from 'vue-router';
|
|
4
|
-
|
|
4
|
+
/** 规范化路径(nginx 等可能加尾部斜杠) */
|
|
5
|
+
export declare const normalizePathForCache: (route: RouteLocationNormalizedLoaded) => string;
|
|
5
6
|
declare const _default: () => {
|
|
6
7
|
tabs: import('vue').Ref<{
|
|
7
8
|
id: string;
|
|
8
9
|
closable: boolean;
|
|
9
10
|
refreshable: boolean;
|
|
10
11
|
iframe: boolean;
|
|
12
|
+
iframeRefreshMode?: import('..').IframeRefreshMode | undefined;
|
|
11
13
|
url?: string | undefined;
|
|
12
14
|
active: boolean;
|
|
13
15
|
pages: {
|
|
@@ -27,6 +29,7 @@ declare const _default: () => {
|
|
|
27
29
|
closable: boolean;
|
|
28
30
|
refreshable: boolean;
|
|
29
31
|
iframe: boolean;
|
|
32
|
+
iframeRefreshMode?: import('..').IframeRefreshMode | undefined;
|
|
30
33
|
url?: string | undefined;
|
|
31
34
|
active: boolean;
|
|
32
35
|
pages: {
|
|
@@ -43,11 +46,12 @@ declare const _default: () => {
|
|
|
43
46
|
title: string;
|
|
44
47
|
}[]>;
|
|
45
48
|
caches: import('vue').Ref<string[], string[]>;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
refreshKey: import('vue').Ref<number, number>;
|
|
50
|
+
excludedCacheIdsForRefresh: import('vue').Ref<string[], string[]>;
|
|
51
|
+
isInitialized: import('vue').Ref<boolean, boolean>;
|
|
52
|
+
setMaxSize: (n: number) => void;
|
|
49
53
|
canAddTab: () => boolean;
|
|
50
|
-
|
|
54
|
+
initialize: (staticTabs: ITabData[]) => void;
|
|
51
55
|
size: () => number;
|
|
52
56
|
active: (id: string, route?: boolean) => void;
|
|
53
57
|
destroy: () => void;
|
|
@@ -59,6 +63,7 @@ declare const _default: () => {
|
|
|
59
63
|
closable: boolean;
|
|
60
64
|
refreshable: boolean;
|
|
61
65
|
iframe: boolean;
|
|
66
|
+
iframeRefreshMode?: import('..').IframeRefreshMode | undefined;
|
|
62
67
|
url?: string | undefined;
|
|
63
68
|
active: boolean;
|
|
64
69
|
pages: {
|
|
@@ -74,7 +79,7 @@ declare const _default: () => {
|
|
|
74
79
|
};
|
|
75
80
|
title: string;
|
|
76
81
|
} | null;
|
|
77
|
-
addTab: (tab: ITabItem) => Promise<
|
|
82
|
+
addTab: (tab: ITabItem) => Promise<boolean>;
|
|
78
83
|
removeTab: (id: string) => string;
|
|
79
84
|
removeAllTabs: () => void;
|
|
80
85
|
removeLeftTabs: (id: string) => void;
|
|
@@ -83,16 +88,17 @@ declare const _default: () => {
|
|
|
83
88
|
hasTab: (id: string) => boolean;
|
|
84
89
|
renewTab: (tab: ITabData) => void;
|
|
85
90
|
addPage: (route: RouteLocationNormalizedLoaded, component: VNode) => DefineComponent;
|
|
86
|
-
addComponent: (id: string, comp: DefineComponent) =>
|
|
87
|
-
getComponent: (id: string) => any;
|
|
88
|
-
removeComponent: (id: string) =>
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
addComponent: (id: string, comp: DefineComponent) => Map<string, DefineComponent<{}, {}, {}, import('vue').ComputedOptions, import('vue').MethodOptions, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{}>>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>>;
|
|
92
|
+
getComponent: (id: string) => DefineComponent<{}, {}, {}, import('vue').ComputedOptions, import('vue').MethodOptions, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{}>>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any> | undefined;
|
|
93
|
+
removeComponent: (id: string) => boolean;
|
|
94
|
+
markCacheForEviction: (cacheName: string) => void;
|
|
95
|
+
evictMarkedCaches: () => void;
|
|
91
96
|
refreshTab: (id: string) => void;
|
|
92
97
|
refreshAllTabs: () => void;
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
iframeRefreshKeys: import('vue').Ref<Record<string, number>, Record<string, number>>;
|
|
99
|
+
addPageScroller: (pageCacheId: string, ...selectorIds: string[]) => void;
|
|
100
|
+
setGlobalScroll: (v: boolean) => void;
|
|
95
101
|
clearSession: () => void;
|
|
96
|
-
setSessionPrefix: (
|
|
102
|
+
setSessionPrefix: (p: string) => void;
|
|
97
103
|
};
|
|
98
104
|
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { RouteLocationPathRaw } from 'vue-router';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* useTabRouter - 标签内路由 Hook
|
|
4
|
+
*
|
|
5
|
+
* 职责:在单个标签内实现「前进/后退」栈式导航,以及滚动位置的记录与恢复
|
|
6
|
+
* 使用范围:仅在标签内的页面组件中使用,依赖 router-view 传入的 tId、pId
|
|
7
|
+
*
|
|
8
|
+
* 主要 API:
|
|
9
|
+
* - forward(to) 前进:push 新页面到该标签的 pages 栈
|
|
10
|
+
* - backward(to, backQuery?) 后退:pop 栈顶、markCacheForEviction,跳转到新栈顶
|
|
11
|
+
* - addScrollTarget(...selectors) 注册需要记录滚动位置的选择器
|
|
12
|
+
*/
|
|
13
|
+
export default function useTabRouter(): {
|
|
4
14
|
forward: (to: RouteLocationPathRaw) => void;
|
|
5
|
-
backward: (to: number | string,
|
|
6
|
-
|
|
15
|
+
backward: (to: number | string, backQuery?: object) => void;
|
|
16
|
+
addScrollTarget: (...selectors: string[]) => void;
|
|
7
17
|
};
|
|
8
|
-
export default _default;
|
package/dist/src/lib/index.d.ts
CHANGED
|
@@ -3,20 +3,21 @@ import { default as StackTab } from './StackTabs.vue';
|
|
|
3
3
|
import { default as IFrame } from './iframe.vue';
|
|
4
4
|
import { default as useTabLoading } from './hooks/useTabLoading';
|
|
5
5
|
import { default as useTabRouter } from './hooks/useTabRouter';
|
|
6
|
-
import { default as
|
|
6
|
+
import { default as useTabActions } from './hooks/useTabActions';
|
|
7
7
|
import { default as TabHeaderButton } from './components/TabHeader/TabHeaderButton.vue';
|
|
8
|
-
|
|
9
8
|
export * from './model/TabModel';
|
|
10
9
|
declare module '@vue/runtime-core' {
|
|
11
10
|
interface GlobalComponents {
|
|
12
11
|
VueStackTabs: typeof StackTab;
|
|
13
12
|
}
|
|
14
13
|
}
|
|
15
|
-
export { IFrame, useTabLoading, useTabRouter,
|
|
14
|
+
export { IFrame, useTabActions, useTabLoading, useTabRouter, TabHeaderButton, StackTab };
|
|
15
|
+
export { postOpenTab, onRefreshRequest, MSG_REFRESH, MSG_OPEN_TAB } from './utils/iframeBridge';
|
|
16
|
+
export type { IframeOpenTabPayload } from './utils/iframeBridge';
|
|
16
17
|
declare const _default: {
|
|
17
18
|
install(Vue: App, options?: {
|
|
18
19
|
locale: string;
|
|
19
|
-
messages:
|
|
20
|
+
messages: Record<string, unknown>;
|
|
20
21
|
}[]): void;
|
|
21
22
|
};
|
|
22
23
|
export default _default;
|
|
@@ -1,14 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TabModel - 标签页数据模型
|
|
3
|
+
*
|
|
4
|
+
* 职责:定义标签、页面、栈结构及右键菜单的数据结构
|
|
5
|
+
* 使用:useTabPanel、useTabActions、ContextMenu 等
|
|
6
|
+
*/
|
|
7
|
+
/** 标签栏滚动方式:滚轮、按钮、或两者 */
|
|
1
8
|
export declare enum TabScrollMode {
|
|
2
9
|
WHEEL = "wheel",
|
|
3
10
|
BUTTON = "button",
|
|
4
11
|
BOTH = "both"
|
|
5
12
|
}
|
|
13
|
+
/** 标签栏滚动条拖拽时的临时状态 */
|
|
6
14
|
export interface DragData {
|
|
7
15
|
thumbLeft: number;
|
|
8
16
|
startScrollLeft: number;
|
|
9
17
|
startThumbLeft: number;
|
|
10
18
|
startPageX: number;
|
|
11
19
|
}
|
|
20
|
+
/** 滚动条滑块计算所需的数据 */
|
|
12
21
|
export interface ScrollData {
|
|
13
22
|
clientWidth: number;
|
|
14
23
|
scrollWidth: number;
|
|
@@ -17,42 +26,50 @@ export interface ScrollData {
|
|
|
17
26
|
export type ScrollEvents = {
|
|
18
27
|
ScrollUpdate: void;
|
|
19
28
|
};
|
|
20
|
-
/**
|
|
21
|
-
* Tab data for open
|
|
22
|
-
*/
|
|
29
|
+
/** 打开标签时传入的完整数据(含 path、query) */
|
|
23
30
|
export interface ITabData extends ITabBase {
|
|
24
31
|
title: string;
|
|
25
32
|
path: string;
|
|
26
33
|
query?: Record<string, string>;
|
|
27
34
|
}
|
|
35
|
+
/** iframe 刷新方式:postMessage 由 iframe 内页自行刷新(不重建 DOM,动画正常);reload 强制重载 iframe */
|
|
36
|
+
export type IframeRefreshMode = 'postMessage' | 'reload';
|
|
37
|
+
/** 标签基础信息(id、title、是否可关闭/刷新、是否 iframe) */
|
|
28
38
|
export interface ITabBase {
|
|
29
39
|
id?: string;
|
|
30
40
|
title: string;
|
|
31
41
|
closable?: boolean;
|
|
32
42
|
refreshable?: boolean;
|
|
33
43
|
iframe?: boolean;
|
|
44
|
+
/** iframe 刷新方式,默认 postMessage */
|
|
45
|
+
iframeRefreshMode?: IframeRefreshMode;
|
|
34
46
|
}
|
|
47
|
+
/** 内部使用的标签项,含 active 状态和 pages 栈 */
|
|
35
48
|
export interface ITabItem extends ITabBase {
|
|
36
49
|
id: string;
|
|
37
50
|
closable: boolean;
|
|
38
51
|
refreshable: boolean;
|
|
39
52
|
iframe: boolean;
|
|
53
|
+
iframeRefreshMode?: IframeRefreshMode;
|
|
40
54
|
url?: string;
|
|
41
55
|
active: boolean;
|
|
42
56
|
pages: Stack<ITabPage>;
|
|
43
57
|
}
|
|
58
|
+
/** 标签内的单个页面(对应 keep-alive 的一个缓存实例) */
|
|
44
59
|
export interface ITabPage {
|
|
45
60
|
id: string;
|
|
46
61
|
tabId: string;
|
|
47
62
|
path: string;
|
|
48
63
|
query?: Record<string, string>;
|
|
49
64
|
}
|
|
65
|
+
/** 右键菜单项:图标、标题、回调、禁用条件 */
|
|
50
66
|
export interface IContextMenu {
|
|
51
67
|
icon?: string;
|
|
52
68
|
title: string;
|
|
53
69
|
callback(id: string): void;
|
|
54
70
|
disabled: (tabData: ITabBase) => boolean;
|
|
55
71
|
}
|
|
72
|
+
/** 使用 Map 实现的栈结构,用于标签内的 pages 页面栈 */
|
|
56
73
|
export declare class Stack<T> {
|
|
57
74
|
private items;
|
|
58
75
|
constructor(items?: T[]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* iframe 与父窗口的 postMessage 桥接
|
|
3
|
+
*
|
|
4
|
+
* 在 iframe 内的页面中引入,用于:
|
|
5
|
+
* - 接收父窗口的刷新指令并执行
|
|
6
|
+
* - 向父窗口发送打开新标签的请求
|
|
7
|
+
*/
|
|
8
|
+
/** 刷新消息:父 -> iframe,iframe 内页面需监听并执行 location.reload() 或自身刷新逻辑 */
|
|
9
|
+
export declare const MSG_REFRESH = "vue-stack-tabs:refresh";
|
|
10
|
+
/** 打开标签消息:iframe -> 父,payload 为 ITabData */
|
|
11
|
+
export declare const MSG_OPEN_TAB = "vue-stack-tabs:openTab";
|
|
12
|
+
export interface IframeOpenTabPayload {
|
|
13
|
+
id?: string;
|
|
14
|
+
title: string;
|
|
15
|
+
path: string;
|
|
16
|
+
query?: Record<string, string>;
|
|
17
|
+
closable?: boolean;
|
|
18
|
+
refreshable?: boolean;
|
|
19
|
+
iframe?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 在 iframe 内调用:向父窗口请求打开新标签
|
|
23
|
+
* @param payload 标签数据,至少需 title、path
|
|
24
|
+
*/
|
|
25
|
+
export declare function postOpenTab(payload: IframeOpenTabPayload): void;
|
|
26
|
+
/**
|
|
27
|
+
* 在 iframe 内调用:注册刷新监听,收到父窗口刷新指令时执行 callback
|
|
28
|
+
* @param callback 默认 location.reload(),可自定义
|
|
29
|
+
* @returns 取消监听的函数
|
|
30
|
+
*/
|
|
31
|
+
export declare function onRefreshRequest(callback?: () => void): () => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 滚动工具函数
|
|
3
|
+
*
|
|
4
|
+
* 职责:页面/标签切换时保存与恢复滚动位置,以及 z-index 计算
|
|
5
|
+
* 使用:useTabPanel 的 scrollPositionsByPageId、TabHeader 滚动条
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* 将指定容器滚动到 (left, top),支持 smooth
|
|
9
|
+
*/
|
|
10
|
+
export declare const scrollTo: ({ wrap, left, top, smooth }: {
|
|
11
|
+
wrap: HTMLElement | null;
|
|
12
|
+
left?: number;
|
|
13
|
+
top?: number;
|
|
14
|
+
smooth?: boolean;
|
|
15
|
+
}) => void;
|
|
16
|
+
/** 将指定元素滚动到容器可视区域内,支持 block/inline 对齐方式 */
|
|
17
|
+
export declare function scrollIntoView({ el, wrap, block, inline }: {
|
|
18
|
+
el: HTMLElement;
|
|
19
|
+
wrap: HTMLElement | {
|
|
20
|
+
value: HTMLElement | null;
|
|
21
|
+
} | null;
|
|
22
|
+
block?: ScrollLogicalPosition;
|
|
23
|
+
inline?: ScrollLogicalPosition;
|
|
24
|
+
}): void;
|
|
25
|
+
/** 获取系统滚动条宽度(用于布局计算) */
|
|
26
|
+
export declare const getScrollbarWidth: () => number;
|
|
27
|
+
/** 获取指定选择器下元素的最大 z-index + 1,用于最大化时置顶 */
|
|
28
|
+
export declare const getMaxZIndex: (key?: string) => number;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ITabBase } from '../model/TabModel';
|
|
2
|
+
/**
|
|
3
|
+
* 标签信息编解码器
|
|
4
|
+
*
|
|
5
|
+
* 职责:将标签元数据压缩为 URL query 可用的短字符串,用于 __tab 参数
|
|
6
|
+
* 格式: id|title|iframe|closable|refreshable,压缩后写入 query.__tab
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* 编码标签基础信息为压缩字符串(用于 query.__tab)
|
|
10
|
+
* @param tabData 标签基础数据
|
|
11
|
+
*/
|
|
12
|
+
export declare const encodeTabInfo: (tabData: ITabBase) => string;
|
|
13
|
+
/** 从 query.__tab 解压并解析为 ITabBase */
|
|
14
|
+
export declare const decodeTabInfo: (encoded: string) => ITabBase;
|
|
15
|
+
/**
|
|
16
|
+
* 根据 tabId + path + query 生成页面缓存 ID
|
|
17
|
+
* 用于 keep-alive 的 include 和 exclude,需稳定且唯一
|
|
18
|
+
*/
|
|
19
|
+
export declare const createPageId: (tabId: string, path: string, query: object) => string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 判断是否为不可嵌入 iframe 的协议
|
|
3
|
+
* @param url - 待检查的 URL 字符串
|
|
4
|
+
* @returns javascript:、data: 等返回 true
|
|
5
|
+
*/
|
|
6
|
+
export declare function isInvalidIframeUrl(url: string): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* 判断 URL 是否为跨域(相对路径或同源视为同域)
|
|
9
|
+
* @param url - 待检查的 URL
|
|
10
|
+
*/
|
|
11
|
+
export declare function isCrossOriginUrl(url: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* 解析 URL 字符串为 path 和 query
|
|
14
|
+
* @param uri 完整 URL 或 path?query 字符串
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseUrl(uri: string): {
|
|
17
|
+
path: string;
|
|
18
|
+
query: Record<string, string>;
|
|
19
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|