vue-stack-tabs 0.1.9 → 0.1.10
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 +2 -2
- package/dist/favicon.svg +9 -9
- package/dist/style.css +1 -1
- package/dist/vue-stack-tabs.es.js +655 -654
- package/dist/vue-stack-tabs.umd.js +10 -10
- package/package.json +4 -4
- package/src/lib/StackTabs.vue +126 -126
- package/src/lib/assets/style/common/mixins.scss +45 -45
- package/src/lib/assets/style/common/var.scss +65 -65
- package/src/lib/assets/style/icon.scss +93 -93
- package/src/lib/assets/style/index.scss +4 -4
- package/src/lib/assets/style/overlayer.scss +40 -40
- package/src/lib/assets/style/stackTab.scss +395 -395
- package/src/lib/assets/style/transition.scss +40 -40
- package/src/lib/banner.ts +51 -51
- package/src/lib/components/ContextMenu/ContextMenuItem.vue +15 -15
- package/src/lib/components/ContextMenu/index.vue +129 -128
- package/src/lib/components/OverlayLoading/Component.vue +191 -188
- package/src/lib/components/OverlayLoading/api.ts +31 -31
- package/src/lib/components/OverlayLoading/helpers.ts +31 -31
- package/src/lib/components/OverlayLoading/index.ts +12 -12
- package/src/lib/components/OverlayLoading/loaders/bars.vue +79 -79
- package/src/lib/components/OverlayLoading/loaders/dots.vue +92 -92
- package/src/lib/components/OverlayLoading/loaders/index.ts +9 -9
- package/src/lib/components/OverlayLoading/loaders/spinner.vue +41 -41
- package/src/lib/components/TabHeader/TabHeaderButton.vue +35 -35
- package/src/lib/components/TabHeader/TabHeaderItem.vue +63 -63
- package/src/lib/components/TabHeader/TabHeaderScroll.vue +240 -240
- package/src/lib/components/TabHeader/index.vue +135 -134
- package/src/lib/hooks/useContextMenu.ts +50 -50
- package/src/lib/hooks/useStackTab.ts +65 -65
- package/src/lib/hooks/useTabLoading.ts +34 -35
- package/src/lib/hooks/useTabRouter.ts +94 -95
- package/src/lib/hooks/useTabpanel.tsx +490 -490
- package/src/lib/i18n/index.ts +72 -72
- package/src/lib/i18n/lang/en.ts +15 -15
- package/src/lib/i18n/lang/zh-CN.ts +15 -15
- package/src/lib/iframe.vue +7 -7
- package/src/lib/index.ts +23 -23
- package/src/lib/model/TabModel.ts +169 -182
- package/src/lib/utils/TabIdHelper.ts +70 -70
- package/src/lib/utils/TabScrollHelper.ts +104 -104
- package/src/lib/utils/UriHelper.ts +22 -22
- package/types/index.d.ts +3 -11
- package/types/src/lib/StackTabs.vue.d.ts +122 -0
- package/types/src/lib/components/ContextMenu/ContextMenuItem.vue.d.ts +17 -0
- package/types/src/lib/components/ContextMenu/index.vue.d.ts +45 -0
- package/types/src/lib/components/OverlayLoading/Component.vue.d.ts +100 -0
- package/types/src/lib/components/OverlayLoading/api.d.ts +5 -0
- package/types/src/lib/components/OverlayLoading/helpers.d.ts +7 -0
- package/types/src/lib/components/OverlayLoading/index.d.ts +6 -0
- package/types/src/lib/components/OverlayLoading/loaders/bars.vue.d.ts +39 -0
- package/types/src/lib/components/OverlayLoading/loaders/dots.vue.d.ts +39 -0
- package/types/src/lib/components/OverlayLoading/loaders/index.d.ts +96 -0
- package/types/src/lib/components/OverlayLoading/loaders/spinner.vue.d.ts +39 -0
- package/types/src/lib/components/TabHeader/TabHeaderButton.vue.d.ts +48 -0
- package/types/src/lib/components/TabHeader/TabHeaderItem.vue.d.ts +21 -0
- package/types/src/lib/components/TabHeader/TabHeaderScroll.vue.d.ts +49 -0
- package/types/src/lib/components/TabHeader/index.vue.d.ts +64 -0
- package/types/{hooks → src/lib/hooks}/useContextMenu.d.ts +8 -2
- package/types/src/lib/hooks/useStackTab.d.ts +8 -0
- package/types/{hooks → src/lib/hooks}/useTabRouter.d.ts +2 -1
- package/types/src/lib/hooks/useTabpanel.d.ts +68 -0
- package/types/src/lib/i18n/index.d.ts +4 -0
- package/types/src/lib/i18n/lang/en.d.ts +16 -0
- package/types/src/lib/i18n/lang/zh-CN.d.ts +16 -0
- package/types/src/lib/iframe.vue.d.ts +2 -0
- package/types/src/lib/index.d.ts +12 -0
- package/types/{model → src/lib/model}/TabModel.d.ts +0 -20
- package/types/{utils → src/lib/utils}/TabScrollHelper.d.ts +3 -3
- package/types/StackTabs.vue.d.ts +0 -2
- package/types/components/ContextMenu/ContextMenuItem.vue.d.ts +0 -2
- package/types/components/ContextMenu/index.vue.d.ts +0 -2
- package/types/components/TabHeader/TabHeaderButton.vue.d.ts +0 -2
- package/types/components/TabHeader/TabHeaderItem.vue.d.ts +0 -2
- package/types/components/TabHeader/TabHeaderScroll.vue.d.ts +0 -2
- package/types/components/TabHeader/index.vue.d.ts +0 -2
- package/types/hooks/useStackTab.d.ts +0 -9
- package/types/iframe.vue.d.ts +0 -2
- /package/types/{banner.d.ts → src/lib/banner.d.ts} +0 -0
- /package/types/{hooks → src/lib/hooks}/useTabLoading.d.ts +0 -0
- /package/types/{utils → src/lib/utils}/TabIdHelper.d.ts +0 -0
- /package/types/{utils → src/lib/utils}/UriHelper.d.ts +0 -0
|
@@ -1,134 +1,135 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="stack-tab__header">
|
|
3
|
-
<slot name="leftButton" />
|
|
4
|
-
<tab-header-scroll
|
|
5
|
-
ref="scroll"
|
|
6
|
-
:space="space"
|
|
7
|
-
:is-scroll-wheel="isScrollWheel"
|
|
8
|
-
:is-scroll-button="isScrollButton"
|
|
9
|
-
>
|
|
10
|
-
<template #default>
|
|
11
|
-
<transition-group
|
|
12
|
-
key="tabItemTrans"
|
|
13
|
-
tag="ul"
|
|
14
|
-
class="stack-tab__nav"
|
|
15
|
-
v-bind="tabTrans"
|
|
16
|
-
appear
|
|
17
|
-
>
|
|
18
|
-
<tab-header-item
|
|
19
|
-
v-for="(item, index) in tabs"
|
|
20
|
-
:key="item.id"
|
|
21
|
-
:contextmenu="contextmenu"
|
|
22
|
-
:item="item"
|
|
23
|
-
@contextmenu.prevent="
|
|
24
|
-
(e: MouseEvent) => showContextMenu(e, item as ITabItem, index, tabs.length)
|
|
25
|
-
"
|
|
26
|
-
@click.middle.prevent="closeTab(item as ITabItem)"
|
|
27
|
-
@close="closeTab"
|
|
28
|
-
@active="activeTab"
|
|
29
|
-
/>
|
|
30
|
-
</transition-group>
|
|
31
|
-
</template>
|
|
32
|
-
</tab-header-scroll>
|
|
33
|
-
<slot name="rightButton" />
|
|
34
|
-
<tab-header-button
|
|
35
|
-
:icon-class="maximum ? 'stack-tab__icon-restore' : 'stack-tab__icon-fullscreen'"
|
|
36
|
-
:title="t('VueStackTab.maximum')"
|
|
37
|
-
@click="maximum = !maximum"
|
|
38
|
-
/>
|
|
39
|
-
<transition name="stack-tab-zoom" appear>
|
|
40
|
-
<context-menu
|
|
41
|
-
v-if="contextMenuShown"
|
|
42
|
-
key="tabMenuTrans"
|
|
43
|
-
:left="contextMenuData.left"
|
|
44
|
-
:top="contextMenuData.top"
|
|
45
|
-
:tab-item="contextMenuData.item as ITabItem"
|
|
46
|
-
:max="contextMenuData.max"
|
|
47
|
-
:index="contextMenuData.index"
|
|
48
|
-
/>
|
|
49
|
-
</transition>
|
|
50
|
-
</div>
|
|
51
|
-
</template>
|
|
52
|
-
|
|
53
|
-
<script lang="ts" setup>
|
|
54
|
-
|
|
55
|
-
import
|
|
56
|
-
import {
|
|
57
|
-
import
|
|
58
|
-
import
|
|
59
|
-
import
|
|
60
|
-
import
|
|
61
|
-
import
|
|
62
|
-
import
|
|
63
|
-
import
|
|
64
|
-
import
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
1
|
+
<template>
|
|
2
|
+
<div class="stack-tab__header">
|
|
3
|
+
<slot name="leftButton" />
|
|
4
|
+
<tab-header-scroll
|
|
5
|
+
ref="scroll"
|
|
6
|
+
:space="space"
|
|
7
|
+
:is-scroll-wheel="isScrollWheel"
|
|
8
|
+
:is-scroll-button="isScrollButton"
|
|
9
|
+
>
|
|
10
|
+
<template #default>
|
|
11
|
+
<transition-group
|
|
12
|
+
key="tabItemTrans"
|
|
13
|
+
tag="ul"
|
|
14
|
+
class="stack-tab__nav"
|
|
15
|
+
v-bind="tabTrans"
|
|
16
|
+
appear
|
|
17
|
+
>
|
|
18
|
+
<tab-header-item
|
|
19
|
+
v-for="(item, index) in tabs"
|
|
20
|
+
:key="item.id"
|
|
21
|
+
:contextmenu="contextmenu"
|
|
22
|
+
:item="item"
|
|
23
|
+
@contextmenu.prevent="
|
|
24
|
+
(e: MouseEvent) => showContextMenu(e, item as ITabItem, index, tabs.length)
|
|
25
|
+
"
|
|
26
|
+
@click.middle.prevent="closeTab(item as ITabItem)"
|
|
27
|
+
@close="closeTab"
|
|
28
|
+
@active="activeTab"
|
|
29
|
+
/>
|
|
30
|
+
</transition-group>
|
|
31
|
+
</template>
|
|
32
|
+
</tab-header-scroll>
|
|
33
|
+
<slot name="rightButton" />
|
|
34
|
+
<tab-header-button
|
|
35
|
+
:icon-class="maximum ? 'stack-tab__icon-restore' : 'stack-tab__icon-fullscreen'"
|
|
36
|
+
:title="t('VueStackTab.maximum')"
|
|
37
|
+
@click="maximum = !maximum"
|
|
38
|
+
/>
|
|
39
|
+
<transition name="stack-tab-zoom" appear>
|
|
40
|
+
<context-menu
|
|
41
|
+
v-if="contextMenuShown"
|
|
42
|
+
key="tabMenuTrans"
|
|
43
|
+
:left="contextMenuData.left"
|
|
44
|
+
:top="contextMenuData.top"
|
|
45
|
+
:tab-item="contextMenuData.item as ITabItem"
|
|
46
|
+
:max="contextMenuData.max"
|
|
47
|
+
:index="contextMenuData.index"
|
|
48
|
+
/>
|
|
49
|
+
</transition>
|
|
50
|
+
</div>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
<script lang="ts" setup>
|
|
54
|
+
// @ts-nocheck
|
|
55
|
+
import { inject, computed, ref } from 'vue'
|
|
56
|
+
import type { TransitionProps, Ref } from 'vue'
|
|
57
|
+
import { TabScrollMode } from '../../model/TabModel'
|
|
58
|
+
import type { ITabItem } from '../../model/TabModel'
|
|
59
|
+
import ContextMenu from '../ContextMenu/index.vue'
|
|
60
|
+
import useContextMenu from '../../hooks/useContextMenu'
|
|
61
|
+
import localeI18n from '../../i18n'
|
|
62
|
+
import useTabpanel from '../../hooks/useTabpanel'
|
|
63
|
+
import TabHeaderItem from './TabHeaderItem.vue'
|
|
64
|
+
import TabHeaderScroll from './TabHeaderScroll.vue'
|
|
65
|
+
import TabHeaderButton from './TabHeaderButton.vue'
|
|
66
|
+
// @ts-ignore
|
|
67
|
+
const { t } = localeI18n().getI18n()
|
|
68
|
+
const maximum = inject<boolean>('maximum')
|
|
69
|
+
const emit = defineEmits(['active'])
|
|
70
|
+
const scroll = ref()
|
|
71
|
+
const { shown: contextMenuShown, contextMenuData, showContextMenu } = useContextMenu()
|
|
72
|
+
|
|
73
|
+
const props = withDefaults(
|
|
74
|
+
defineProps<{
|
|
75
|
+
space: number
|
|
76
|
+
// tab的滚动方式
|
|
77
|
+
tabScrollMode?: TabScrollMode
|
|
78
|
+
// tab动画
|
|
79
|
+
tabTransition?: string | TransitionProps
|
|
80
|
+
contextmenu?: boolean | object
|
|
81
|
+
max?: number
|
|
82
|
+
}>(),
|
|
83
|
+
{
|
|
84
|
+
tabTransition: () => {
|
|
85
|
+
return {
|
|
86
|
+
name: 'stack-tab-zoom'
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
tabScrollMode: TabScrollMode.BOTH,
|
|
90
|
+
contextmenu: true,
|
|
91
|
+
max: 20
|
|
92
|
+
}
|
|
93
|
+
)
|
|
94
|
+
const { removeTab, active, tabs } = useTabpanel()
|
|
95
|
+
|
|
96
|
+
// 转换tab动画
|
|
97
|
+
const tabTrans = computed<TransitionProps>(() => {
|
|
98
|
+
if (typeof props.tabTransition === 'string') {
|
|
99
|
+
return {
|
|
100
|
+
name: props.tabTransition
|
|
101
|
+
} as TransitionProps
|
|
102
|
+
}
|
|
103
|
+
return props.tabTransition as TransitionProps
|
|
104
|
+
})
|
|
105
|
+
// 判断是否有滚动按钮
|
|
106
|
+
const isScrollButton = computed<boolean>(() => {
|
|
107
|
+
return props.tabScrollMode === TabScrollMode.BOTH || props.tabScrollMode === TabScrollMode.BUTTON
|
|
108
|
+
})
|
|
109
|
+
// 判断是否可以使用滚轮
|
|
110
|
+
const isScrollWheel =
|
|
111
|
+
props.tabScrollMode === TabScrollMode.BOTH || props.tabScrollMode === TabScrollMode.WHEEL
|
|
112
|
+
|
|
113
|
+
// 关闭前,先判断是不最先中状态
|
|
114
|
+
const closeTab = (item: ITabItem) => {
|
|
115
|
+
// emit('close', item)
|
|
116
|
+
if (item.closable) {
|
|
117
|
+
const activeId = removeTab(item.id)
|
|
118
|
+
emit('active', activeId)
|
|
119
|
+
}
|
|
120
|
+
contextMenuShown.value = false
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const activeTab = (item: ITabItem, curActiveTab: Ref<HTMLElement>) => {
|
|
124
|
+
if (scroll.value) {
|
|
125
|
+
if (!scroll.value!.isInView(curActiveTab.value)) {
|
|
126
|
+
scroll.value!.scrollIntoView(curActiveTab.value)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
active(item.id)
|
|
130
|
+
emit('active', item.id)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
</script>
|
|
134
|
+
|
|
135
|
+
<style scoped></style>
|
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import { onUnmounted, onMounted, ref, reactive, nextTick } from 'vue'
|
|
2
|
-
import type { ITabItem } from '../model/TabModel'
|
|
3
|
-
export default () => {
|
|
4
|
-
const contextMenuData = reactive({
|
|
5
|
-
item: {},
|
|
6
|
-
index: -1,
|
|
7
|
-
left: 0,
|
|
8
|
-
top: 0,
|
|
9
|
-
max: 0
|
|
10
|
-
})
|
|
11
|
-
const shown = ref<boolean>(false)
|
|
12
|
-
|
|
13
|
-
onMounted(() => {
|
|
14
|
-
document.addEventListener('click', clickOutSide)
|
|
15
|
-
})
|
|
16
|
-
onUnmounted(() => {
|
|
17
|
-
document.removeEventListener('click', clickOutSide)
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
const showContextMenu = async (e: MouseEvent, item: ITabItem, index: number, max: number) => {
|
|
21
|
-
// 关闭已打开的菜单
|
|
22
|
-
shown.value = false
|
|
23
|
-
|
|
24
|
-
await nextTick(() => {
|
|
25
|
-
const { clientY: top, clientX: left } = e
|
|
26
|
-
shown.value = true
|
|
27
|
-
Object.assign(contextMenuData, { item, index, top, left, max })
|
|
28
|
-
|
|
29
|
-
console.log('showContextMenu in callback')
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
// .then(() => {
|
|
33
|
-
|
|
34
|
-
// })
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const clickOutSide = (ev: MouseEvent) => {
|
|
38
|
-
const classList = (ev.target as Element).classList
|
|
39
|
-
if (classList.contains('stack-tab__contextmenu')) {
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
shown.value = false
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
shown,
|
|
47
|
-
contextMenuData,
|
|
48
|
-
showContextMenu
|
|
49
|
-
}
|
|
50
|
-
}
|
|
1
|
+
import { onUnmounted, onMounted, ref, reactive, nextTick } from 'vue'
|
|
2
|
+
import type { ITabItem } from '../model/TabModel'
|
|
3
|
+
export default () => {
|
|
4
|
+
const contextMenuData = reactive({
|
|
5
|
+
item: {},
|
|
6
|
+
index: -1,
|
|
7
|
+
left: 0,
|
|
8
|
+
top: 0,
|
|
9
|
+
max: 0
|
|
10
|
+
})
|
|
11
|
+
const shown = ref<boolean>(false)
|
|
12
|
+
|
|
13
|
+
onMounted(() => {
|
|
14
|
+
document.addEventListener('click', clickOutSide)
|
|
15
|
+
})
|
|
16
|
+
onUnmounted(() => {
|
|
17
|
+
document.removeEventListener('click', clickOutSide)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const showContextMenu = async (e: MouseEvent, item: ITabItem, index: number, max: number) => {
|
|
21
|
+
// 关闭已打开的菜单
|
|
22
|
+
shown.value = false
|
|
23
|
+
|
|
24
|
+
await nextTick(() => {
|
|
25
|
+
const { clientY: top, clientX: left } = e
|
|
26
|
+
shown.value = true
|
|
27
|
+
Object.assign(contextMenuData, { item, index, top, left, max })
|
|
28
|
+
|
|
29
|
+
console.log('showContextMenu in callback')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
// .then(() => {
|
|
33
|
+
|
|
34
|
+
// })
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const clickOutSide = (ev: MouseEvent) => {
|
|
38
|
+
const classList = (ev.target as Element).classList
|
|
39
|
+
if (classList.contains('stack-tab__contextmenu')) {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
shown.value = false
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
shown,
|
|
47
|
+
contextMenuData,
|
|
48
|
+
showContextMenu
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
import { useRouter } from 'vue-router'
|
|
2
|
-
import useTabpanel from '../hooks/useTabpanel'
|
|
3
|
-
import { throttle } from 'lodash-es'
|
|
4
|
-
import type { ITabData } from '../model/TabModel'
|
|
5
|
-
import { defu } from 'defu'
|
|
6
|
-
import { encodeTabInfo } from '../utils/TabIdHelper'
|
|
7
|
-
import { uriDecode } from '../utils/UriHelper'
|
|
8
|
-
import { ulid } from 'ulidx'
|
|
9
|
-
let iframePath: string
|
|
10
|
-
export default () => {
|
|
11
|
-
const router = useRouter()
|
|
12
|
-
const { active, hasTab, pageShown, reset } = useTabpanel()
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* 打开新的TAB页面
|
|
16
|
-
* @param tab
|
|
17
|
-
* @param to
|
|
18
|
-
*/
|
|
19
|
-
const openNewTab = throttle(async (tab: ITabData) => {
|
|
20
|
-
if (!pageShown.value) {
|
|
21
|
-
return
|
|
22
|
-
}
|
|
23
|
-
const tabInfo = defu(tab, { refreshable: true, closable: true, iframe: false })
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* In the function of openNewTab, if the tab already 'ACTIVE' then do nothing.
|
|
27
|
-
*/
|
|
28
|
-
if (hasTab(tabInfo.id!)) {
|
|
29
|
-
active(tabInfo.id!)
|
|
30
|
-
return
|
|
31
|
-
}
|
|
32
|
-
if (!tabInfo.id) {
|
|
33
|
-
tabInfo.id = ulid()
|
|
34
|
-
}
|
|
35
|
-
const __tab = encodeTabInfo(tabInfo)
|
|
36
|
-
let query = defu(
|
|
37
|
-
{
|
|
38
|
-
__tab
|
|
39
|
-
},
|
|
40
|
-
tab.query
|
|
41
|
-
) as Record<string, string>
|
|
42
|
-
let path
|
|
43
|
-
if (!tab.iframe) {
|
|
44
|
-
const url = uriDecode(tab.path)
|
|
45
|
-
path = url.path
|
|
46
|
-
query = defu(url.query, query)
|
|
47
|
-
} else {
|
|
48
|
-
const __src = encodeURIComponent(tab.path as string)
|
|
49
|
-
path = iframePath
|
|
50
|
-
query['__src'] = __src
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
router.push({
|
|
54
|
-
path,
|
|
55
|
-
query
|
|
56
|
-
})
|
|
57
|
-
return tabInfo.id
|
|
58
|
-
}, 500)
|
|
59
|
-
|
|
60
|
-
const setIFramePath = (path: string) => {
|
|
61
|
-
iframePath = path
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return { openNewTab, setIFramePath, active, reset }
|
|
65
|
-
}
|
|
1
|
+
import { useRouter } from 'vue-router'
|
|
2
|
+
import useTabpanel from '../hooks/useTabpanel'
|
|
3
|
+
import { throttle } from 'lodash-es'
|
|
4
|
+
import type { ITabData } from '../model/TabModel'
|
|
5
|
+
import { defu } from 'defu'
|
|
6
|
+
import { encodeTabInfo } from '../utils/TabIdHelper'
|
|
7
|
+
import { uriDecode } from '../utils/UriHelper'
|
|
8
|
+
import { ulid } from 'ulidx'
|
|
9
|
+
let iframePath: string
|
|
10
|
+
export default () => {
|
|
11
|
+
const router = useRouter()
|
|
12
|
+
const { active, hasTab, pageShown, reset } = useTabpanel()
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 打开新的TAB页面
|
|
16
|
+
* @param tab
|
|
17
|
+
* @param to
|
|
18
|
+
*/
|
|
19
|
+
const openNewTab = throttle(async (tab: ITabData) => {
|
|
20
|
+
if (!pageShown.value) {
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
const tabInfo = defu(tab, { refreshable: true, closable: true, iframe: false })
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* In the function of openNewTab, if the tab already 'ACTIVE' then do nothing.
|
|
27
|
+
*/
|
|
28
|
+
if (hasTab(tabInfo.id!)) {
|
|
29
|
+
active(tabInfo.id!)
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
if (!tabInfo.id) {
|
|
33
|
+
tabInfo.id = ulid()
|
|
34
|
+
}
|
|
35
|
+
const __tab = encodeTabInfo(tabInfo)
|
|
36
|
+
let query = defu(
|
|
37
|
+
{
|
|
38
|
+
__tab
|
|
39
|
+
},
|
|
40
|
+
tab.query
|
|
41
|
+
) as Record<string, string>
|
|
42
|
+
let path
|
|
43
|
+
if (!tab.iframe) {
|
|
44
|
+
const url = uriDecode(tab.path)
|
|
45
|
+
path = url.path
|
|
46
|
+
query = defu(url.query, query)
|
|
47
|
+
} else {
|
|
48
|
+
const __src = encodeURIComponent(tab.path as string)
|
|
49
|
+
path = iframePath
|
|
50
|
+
query['__src'] = __src
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
router.push({
|
|
54
|
+
path,
|
|
55
|
+
query
|
|
56
|
+
})
|
|
57
|
+
return tabInfo.id
|
|
58
|
+
}, 500)
|
|
59
|
+
|
|
60
|
+
const setIFramePath = (path: string) => {
|
|
61
|
+
iframePath = path
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { openNewTab, setIFramePath, active, reset }
|
|
65
|
+
}
|
|
@@ -1,35 +1,34 @@
|
|
|
1
|
-
import { useLoading } from '../components/OverlayLoading'
|
|
2
|
-
import type
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
loadingInstance
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
}
|
|
1
|
+
import { useLoading } from '../components/OverlayLoading'
|
|
2
|
+
import { type ComponentInternalInstance, getCurrentInstance, onUnmounted } from 'vue'
|
|
3
|
+
|
|
4
|
+
export default () => {
|
|
5
|
+
const $loading = useLoading()
|
|
6
|
+
const { attrs } = getCurrentInstance() as ComponentInternalInstance
|
|
7
|
+
let loadingInstance: any | null = null
|
|
8
|
+
onUnmounted(() => {
|
|
9
|
+
closeTabLoading()
|
|
10
|
+
})
|
|
11
|
+
const openTabLoading = () => {
|
|
12
|
+
const container = document.querySelector(`#${attrs.tId}`)
|
|
13
|
+
if (loadingInstance === null) {
|
|
14
|
+
loadingInstance = $loading.show({
|
|
15
|
+
canCancel: false,
|
|
16
|
+
isFullPage: false,
|
|
17
|
+
height: 85,
|
|
18
|
+
width: 85,
|
|
19
|
+
loader: 'spinner',
|
|
20
|
+
color: '#007bff',
|
|
21
|
+
|
|
22
|
+
container: container!
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const closeTabLoading = () => {
|
|
28
|
+
if (loadingInstance !== null) {
|
|
29
|
+
loadingInstance.hide()
|
|
30
|
+
loadingInstance = null
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { openTabLoading, closeTabLoading }
|
|
34
|
+
}
|