vue-stack-tabs 0.1.11 → 0.1.13
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/{types → dist}/src/lib/hooks/useStackTab.d.ts +2 -2
- package/{types → dist}/src/lib/hooks/useTabpanel.d.ts +6 -2
- package/{types → dist}/src/lib/index.d.ts +7 -1
- package/{types → dist}/src/lib/model/TabModel.d.ts +2 -1
- package/dist/style.css +1 -1
- package/dist/vue-stack-tabs.es.js +2340 -2321
- package/dist/vue-stack-tabs.umd.js +10 -10
- package/package.json +3 -4
- package/src/lib/StackTabs.vue +136 -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 -129
- package/src/lib/components/OverlayLoading/Component.vue +182 -191
- 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 -135
- package/src/lib/hooks/useContextMenu.ts +50 -50
- package/src/lib/hooks/useStackTab.ts +74 -65
- package/src/lib/hooks/useTabLoading.ts +34 -34
- package/src/lib/hooks/useTabRouter.ts +94 -94
- package/src/lib/hooks/useTabpanel.tsx +516 -491
- 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 +32 -23
- package/src/lib/model/TabModel.ts +178 -169
- 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 → dist}/index.d.ts +0 -0
- /package/{types → dist}/src/lib/StackTabs.vue.d.ts +0 -0
- /package/{types → dist}/src/lib/banner.d.ts +0 -0
- /package/{types → dist}/src/lib/components/ContextMenu/ContextMenuItem.vue.d.ts +0 -0
- /package/{types → dist}/src/lib/components/ContextMenu/index.vue.d.ts +0 -0
- /package/{types → dist}/src/lib/components/OverlayLoading/Component.vue.d.ts +0 -0
- /package/{types → dist}/src/lib/components/OverlayLoading/api.d.ts +0 -0
- /package/{types → dist}/src/lib/components/OverlayLoading/helpers.d.ts +0 -0
- /package/{types → dist}/src/lib/components/OverlayLoading/index.d.ts +0 -0
- /package/{types → dist}/src/lib/components/OverlayLoading/loaders/bars.vue.d.ts +0 -0
- /package/{types → dist}/src/lib/components/OverlayLoading/loaders/dots.vue.d.ts +0 -0
- /package/{types → dist}/src/lib/components/OverlayLoading/loaders/index.d.ts +0 -0
- /package/{types → dist}/src/lib/components/OverlayLoading/loaders/spinner.vue.d.ts +0 -0
- /package/{types → dist}/src/lib/components/TabHeader/TabHeaderButton.vue.d.ts +0 -0
- /package/{types → dist}/src/lib/components/TabHeader/TabHeaderItem.vue.d.ts +0 -0
- /package/{types → dist}/src/lib/components/TabHeader/TabHeaderScroll.vue.d.ts +0 -0
- /package/{types → dist}/src/lib/components/TabHeader/index.vue.d.ts +0 -0
- /package/{types → dist}/src/lib/hooks/useContextMenu.d.ts +0 -0
- /package/{types → dist}/src/lib/hooks/useTabLoading.d.ts +0 -0
- /package/{types → dist}/src/lib/hooks/useTabRouter.d.ts +0 -0
- /package/{types → dist}/src/lib/i18n/index.d.ts +0 -0
- /package/{types → dist}/src/lib/i18n/lang/en.d.ts +0 -0
- /package/{types → dist}/src/lib/i18n/lang/zh-CN.d.ts +0 -0
- /package/{types → dist}/src/lib/iframe.vue.d.ts +0 -0
- /package/{types → dist}/src/lib/utils/TabIdHelper.d.ts +0 -0
- /package/{types → dist}/src/lib/utils/TabScrollHelper.d.ts +0 -0
- /package/{types → dist}/src/lib/utils/UriHelper.d.ts +0 -0
|
@@ -1,135 +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
|
-
// @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
|
+
<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,74 @@
|
|
|
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(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
path
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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,canAddTab } = useTabpanel()
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 打开新的TAB页面
|
|
16
|
+
* @param tab
|
|
17
|
+
* @param to
|
|
18
|
+
*/
|
|
19
|
+
const openNewTab = throttle((tab: ITabData) => {
|
|
20
|
+
return new Promise((resolve, reject)=>{
|
|
21
|
+
if(!canAddTab()){
|
|
22
|
+
reject()
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
if (!pageShown.value) {
|
|
26
|
+
reject()
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
const tabInfo = defu(tab, { refreshable: true, closable: true, iframe: false })
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* In the function of openNewTab, if the tab already 'ACTIVE' then do nothing.
|
|
33
|
+
*/
|
|
34
|
+
if (hasTab(tabInfo.id!)) {
|
|
35
|
+
active(tabInfo.id!)
|
|
36
|
+
resolve(tabInfo.id)
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
if (!tabInfo.id) {
|
|
40
|
+
tabInfo.id = ulid()
|
|
41
|
+
}
|
|
42
|
+
const __tab = encodeTabInfo(tabInfo)
|
|
43
|
+
let query = defu(
|
|
44
|
+
{
|
|
45
|
+
__tab
|
|
46
|
+
},
|
|
47
|
+
tab.query
|
|
48
|
+
) as Record<string, string>
|
|
49
|
+
let path
|
|
50
|
+
if (!tab.iframe) {
|
|
51
|
+
const url = uriDecode(tab.path)
|
|
52
|
+
path = url.path
|
|
53
|
+
query = defu(url.query, query)
|
|
54
|
+
} else {
|
|
55
|
+
const __src = encodeURIComponent(tab.path as string)
|
|
56
|
+
path = iframePath
|
|
57
|
+
query['__src'] = __src
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
router.push({
|
|
61
|
+
path,
|
|
62
|
+
query
|
|
63
|
+
})
|
|
64
|
+
resolve(tabInfo.id)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
}, 500)
|
|
68
|
+
|
|
69
|
+
const setIFramePath = (path: string) => {
|
|
70
|
+
iframePath = path
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { openNewTab, setIFramePath, active, reset }
|
|
74
|
+
}
|
|
@@ -1,34 +1,34 @@
|
|
|
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
|
-
}
|
|
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
|
+
}
|