vue-stack-tabs 0.1.19 → 0.1.21

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.
@@ -1,124 +1,129 @@
1
- <script lang="ts" setup>
2
- import { onBeforeMount, onUnmounted, provide, ref } from 'vue'
3
- import type { TransitionProps, DefineComponent, VNode } from 'vue'
4
- import { type RouteLocationNormalizedLoaded } from 'vue-router'
5
- import { getMaxZIndex } from './utils/TabScrollHelper'
6
- import { type ITabData, TabScrollMode } from './model/TabModel'
7
- import TabHeader from './components/TabHeader/index.vue'
8
- import useTabpanel from './hooks/useTabpanel'
9
- import useStackTab from './hooks/useStackTab'
10
- const { tabs, pageShown, caches, addPage, destroy, initial,setMaxSize } = useTabpanel()
11
- const emit = defineEmits(['onActive'])
12
- const props = withDefaults(
13
- defineProps<{
14
- // 初始页签数据
15
- defaultTabs?: ITabData[]
16
- // 最大打开数量
17
- max?: number
18
- // 新页加入哪个位置
19
- append?: string
20
- // 右键菜单
21
- contextmenu?: boolean | object
22
- // 页面转场效果
23
- pageTransition?: string
24
- // 标签转场效果
25
- tabTransition?: string | TransitionProps
26
- // tab 滚动效果
27
- tabScrollMode?: TabScrollMode
28
- width?: string
29
- height?: string
30
- i18n?: { locale?: string; messages?: object }
31
- messages?: any
32
- reloadable?: boolean
33
- closable?: boolean
34
- space?: number
35
- iframePath: string
36
- }>(),
37
- {
38
- defaultTabs: () => [],
39
- max: 20,
40
- append: 'last',
41
- contextmenu: true,
42
- tabTransition: 'stack-tab-zoom',
43
- pageTransition: 'stack-tab-swap',
44
- tabScrollMode: TabScrollMode.BOTH,
45
- width: '100%',
46
- height: '100%',
47
- i18n: () => ({ locale: 'zh-CN', messages: {} }),
48
- reloadable: true,
49
- closable: true,
50
- space: 300
51
- }
52
- )
53
- // provide('locales', { ...props.i18n })
54
- // 最大化,并向下传递
55
- const maximum = ref<boolean>(false)
56
- provide('maximum', maximum)
57
- const { setIFramePath } = useStackTab()
58
- setIFramePath(props.iframePath)
59
- onBeforeMount(() => {
60
- console.log('on Before mount')
61
- initial(props.defaultTabs)
62
- })
63
- const tabWrapper = (route: RouteLocationNormalizedLoaded, component: VNode): DefineComponent => {
64
- // return defineAsyncComponent(() => addPage(route, component))
65
- return addPage(route, component)
66
- }
67
- const onTabActive = (id: string) => {
68
- emit('onActive', id)
69
- }
70
- setMaxSize(props.max)
71
- onUnmounted(() => {
72
- destroy()
73
- })
74
-
75
- </script>
76
- <template>
77
- <div
78
- class="stack-tab"
79
- :style="{
80
- width: width,
81
- height: height,
82
- 'z-index': maximum ? getMaxZIndex('body *:not(.stack-tab,.stack-tab *)') : undefined
83
- }"
84
- :class="{ 'stack-tab__maximum': maximum }"
85
- >
86
- <tab-header :space="space" @active="onTabActive" :tab-transition="tabTransition" :max="max">
87
- <template #leftButton>
88
- <slot name="leftButton" />
89
- </template>
90
- <template #rightButton>
91
- <slot name="rightButton" />
92
- </template>
93
- </tab-header>
94
- <div class="stack-tab__container">
95
- <router-view v-slot="{ Component, route }">
96
- <transition :name="pageTransition" @after-leave="pageShown=true" mode="out-in">
97
- <keep-alive :include="caches">
98
- <suspense>
99
- <template #default>
100
- <component
101
- :is="tabWrapper(route, Component)"
102
- v-if="pageShown"
103
- :key="route.fullPath"
104
- />
105
- </template>
106
- <template #fallback> Loading.... </template>
107
- </suspense>
108
- </keep-alive>
109
- </transition>
110
- </router-view>
111
- <transition-group :name="pageTransition" appear>
112
- <iframe
113
- v-for="frame of tabs.filter((item) => item.iframe)"
114
- v-show="frame.active && pageShown"
115
- :key="frame.id"
116
- class="stack-tab__iframe"
117
- :src="/^(javascript|data):/i.test(frame.url ?? '') ? 'about:blank' : frame.url"
118
- frameborder="0"
119
- />
120
- </transition-group>
121
- </div>
122
- </div>
123
- </template>
124
- <style scoped></style>
1
+ <script lang="ts" setup>
2
+ import { onBeforeMount, onUnmounted, provide, ref } from 'vue'
3
+ import type { TransitionProps, DefineComponent, VNode } from 'vue'
4
+ import { type RouteLocationNormalizedLoaded } from 'vue-router'
5
+ import { getMaxZIndex } from './utils/TabScrollHelper'
6
+ import { type ITabData, TabScrollMode } from './model/TabModel'
7
+ import TabHeader from './components/TabHeader/index.vue'
8
+ import useTabpanel from './hooks/useTabpanel'
9
+ import useStackTab from './hooks/useStackTab'
10
+ import { useI18n } from 'vue-i18n-lite'
11
+ const { tabs, pageShown, caches, addPage, destroy, initial, setMaxSize, setGlobalScroll } =
12
+ useTabpanel()
13
+ const emit = defineEmits(['onActive', 'onPageLoaded'])
14
+ const props = withDefaults(
15
+ defineProps<{
16
+ // 初始页签数据
17
+ defaultTabs?: ITabData[]
18
+ // 最大打开数量
19
+ max?: number
20
+ // 新页加入哪个位置
21
+ append?: string
22
+ // 右键菜单
23
+ contextmenu?: boolean | object
24
+ // 页面转场效果
25
+ pageTransition?: string
26
+ // 标签转场效果
27
+ tabTransition?: string | TransitionProps
28
+ // tab 滚动效果
29
+ tabScrollMode?: TabScrollMode
30
+ width?: string
31
+ height?: string
32
+ i18n?: string
33
+ space?: number
34
+ globalScroll: boolean
35
+ iframePath: string
36
+ }>(),
37
+ {
38
+ defaultTabs: () => [],
39
+ max: 20,
40
+ append: 'last',
41
+ contextmenu: true,
42
+ tabTransition: 'stack-tab-zoom',
43
+ pageTransition: 'stack-tab-swap',
44
+ tabScrollMode: TabScrollMode.BOTH,
45
+ width: '100%',
46
+ height: '100%',
47
+ i18n: 'zh-CN',
48
+ space: 300,
49
+ globalScroll: false
50
+ }
51
+ )
52
+ // provide('locales', { ...props.i18n })
53
+ // 最大化,并向下传递
54
+ const { changeLocale } = useI18n()
55
+ const maximum = ref<boolean>(false)
56
+ provide('maximum', maximum)
57
+ const { setIFramePath } = useStackTab()
58
+ setIFramePath(props.iframePath)
59
+ setGlobalScroll(props.globalScroll)
60
+ changeLocale(props.i18n)
61
+ onBeforeMount(() => {
62
+ console.log('on Before mount')
63
+ initial(props.defaultTabs)
64
+ })
65
+ const tabWrapper = (route: RouteLocationNormalizedLoaded, component: VNode): DefineComponent => {
66
+ // return defineAsyncComponent(() => addPage(route, component))
67
+ return addPage(route, component)
68
+ }
69
+ const onTabActive = (id: string) => {
70
+ emit('onActive', id)
71
+ }
72
+ setMaxSize(props.max)
73
+ onUnmounted(() => {
74
+ destroy()
75
+ })
76
+ const onComponentLoaded = () => {
77
+ emit('onPageLoaded')
78
+ }
79
+ </script>
80
+ <template>
81
+ <div
82
+ class="stack-tab"
83
+ :style="{
84
+ width: width,
85
+ height: height,
86
+ 'z-index': maximum ? getMaxZIndex('body *:not(.stack-tab,.stack-tab *)') : undefined
87
+ }"
88
+ :class="{ 'stack-tab__maximum': maximum }"
89
+ >
90
+ <tab-header :space="space" @active="onTabActive" :tab-transition="tabTransition" :max="max">
91
+ <template #leftButton>
92
+ <slot name="leftButton" />
93
+ </template>
94
+ <template #rightButton>
95
+ <slot name="rightButton" />
96
+ </template>
97
+ </tab-header>
98
+ <div class="stack-tab__container">
99
+ <router-view v-slot="{ Component, route }">
100
+ <transition :name="pageTransition" @after-leave="pageShown = true" mode="out-in">
101
+ <keep-alive :include="caches">
102
+ <suspense>
103
+ <template #default>
104
+ <component
105
+ :is="tabWrapper(route, Component)"
106
+ v-if="pageShown"
107
+ :key="route.fullPath"
108
+ @on-loaded="onComponentLoaded"
109
+ />
110
+ </template>
111
+ <template #fallback> Loading.... </template>
112
+ </suspense>
113
+ </keep-alive>
114
+ </transition>
115
+ </router-view>
116
+ <transition-group :name="pageTransition" appear>
117
+ <iframe
118
+ v-for="frame of tabs.filter((item) => item.iframe)"
119
+ v-show="frame.active && pageShown"
120
+ :key="frame.id"
121
+ class="stack-tab__iframe"
122
+ :src="/^(javascript|data):/i.test(frame.url ?? '') ? 'about:blank' : frame.url"
123
+ frameborder="0"
124
+ />
125
+ </transition-group>
126
+ </div>
127
+ </div>
128
+ </template>
129
+ <style scoped></style>
@@ -1,40 +1,40 @@
1
- /*
2
- transition 过渡样式
3
- */
4
- .stack-tab-zoom {
5
- &-enter-active,
6
- &-leave-active {
7
- transition: all 0.3s ease-in-out;
8
- }
9
-
10
- &-enter-from,
11
- &-leave-to {
12
- transform: scale(0);
13
- opacity: 0;
14
- }
15
- }
16
-
17
- /*
18
- 页面交换
19
- */
20
- .stack-tab-swap {
21
- $trans: 30px;
22
-
23
- &-enter-active,
24
- &-leave-active {
25
- transition: all 0.3s ease-in-out;
26
- }
27
-
28
- &-enter-from,
29
- &-leave-to {
30
- opacity: 0;
31
- }
32
-
33
- &-enter-from {
34
- transform: translateX(-$trans);
35
- }
36
-
37
- &-leave-to {
38
- transform: translateX($trans);
39
- }
40
- }
1
+ /*
2
+ transition 过渡样式
3
+ */
4
+ .stack-tab-zoom {
5
+ &-enter-active,
6
+ &-leave-active {
7
+ transition: all 0.3s ease-in-out;
8
+ }
9
+
10
+ &-enter-from,
11
+ &-leave-to {
12
+ transform: scale(0);
13
+ opacity: 0;
14
+ }
15
+ }
16
+
17
+ /*
18
+ 页面交换
19
+ */
20
+ .stack-tab-swap {
21
+ $trans: 30px;
22
+
23
+ &-enter-active,
24
+ &-leave-active {
25
+ transition: all 0.3s ease-in-out;
26
+ }
27
+
28
+ &-enter-from,
29
+ &-leave-to {
30
+ opacity: 0;
31
+ }
32
+
33
+ &-enter-from {
34
+ transform: translateX(-$trans);
35
+ }
36
+
37
+ &-leave-to {
38
+ transform: translateX($trans);
39
+ }
40
+ }
@@ -26,13 +26,13 @@
26
26
  />
27
27
  <context-menu-item
28
28
  icon="stack-tab__icon-close-lefts svg-mask"
29
- :title="t('VueStackTab.closeLefts')"
29
+ :title="t('VueStackTab.closeLeft')"
30
30
  :disabled="index <= 0 ? 'disabled' : null"
31
31
  @click="removeLeftTabs(tabItem.id)"
32
32
  />
33
33
  <context-menu-item
34
34
  icon="stack-tab__icon-close-rights svg-mask"
35
- :title="t('VueStackTab.closeRights')"
35
+ :title="t('VueStackTab.closeRight')"
36
36
  :disabled="index >= max - 1 ? 'disabled' : null"
37
37
  @click="removeRightTabs(tabItem.id)"
38
38
  />
@@ -1,20 +1,20 @@
1
- <template>
2
- <div v-if="loading" class="stack-tab-loading-mask">
3
- <div class="stack-tab-loading--spin turn" />
4
- </div>
5
- </template>
6
- <script setup lang="ts">
7
- import { ref } from 'vue'
8
- import { MittType, useEmitter } from '../hooks/useTabMitt'
9
- const props = defineProps<{
10
- tId: string
11
- }>()
12
- const emitter = useEmitter()
13
- const loading = ref<boolean>(false)
14
- emitter.on(MittType.PAGE_LOADING, ({ tId, value }: any) => {
15
- if (tId === props.tId) {
16
- loading.value = value
17
- }
18
- })
19
- </script>
20
- <style scoped></style>
1
+ <template>
2
+ <div v-if="loading" class="stack-tab-loading-mask">
3
+ <div class="stack-tab-loading--spin turn" />
4
+ </div>
5
+ </template>
6
+ <script setup lang="ts">
7
+ import { ref } from 'vue'
8
+ import { MittType, useEmitter } from '../hooks/useTabMitt'
9
+ const props = defineProps<{
10
+ tId: string
11
+ }>()
12
+ const emitter = useEmitter()
13
+ const loading = ref<boolean>(false)
14
+ emitter.on(MittType.PAGE_LOADING, ({ tId, value }: any) => {
15
+ if (tId === props.tId) {
16
+ loading.value = value
17
+ }
18
+ })
19
+ </script>
20
+ <style scoped></style>
@@ -1,69 +1,69 @@
1
- <template>
2
- <li
3
- ref="curtab"
4
- class="stack-tab__item"
5
- :class="{
6
- 'is-active': item.active,
7
- 'is-icon': item.closable
8
- }"
9
- @click="activeTab(true)"
10
- >
11
- <!-- <div v-if="!!icon" class="stack-tab__item-icon" :class="icon"></div>-->
12
- <div class="stack-tab__item-title">
13
- <div class="stack-tab__item-title-content" :title="title">
14
- {{ title }}
15
- </div>
16
- </div>
17
- <div
18
- v-if="item.closable"
19
- class="stack-tab__icon-close-fill stack-tab__item-button"
20
- :title="t('VueStackTab.close')"
21
- @click.stop="closeTab"
22
- />
23
- </li>
24
- </template>
25
-
26
- <script setup lang="ts">
27
- import { computed, ref } from 'vue'
28
- import type { ITabItem } from '@/lib/model/TabModel'
29
- import { MittType, useEmitter } from '../../hooks/useTabMitt'
30
- import { useI18n } from 'vue-i18n-lite'
31
- // 消息
32
- const emit = defineEmits(['close', 'active'])
33
- const emitter = useEmitter()
34
- const { t } = useI18n()
35
- const curtab = ref<HTMLElement>()
36
- const props = defineProps<{
37
- item: ITabItem
38
- }>()
39
- /**
40
- * 如果Active为true,就看看
41
- */
42
- // watch(
43
- // () => props.item.active,
44
- // (val) => {
45
- // if (val) {
46
- // activeTab()
47
- // }
48
- // }
49
- // )
50
- emitter.on(MittType.TAB_ACTIVE, ({ id, isRoute }: any) => {
51
- if (props.item.id === id) {
52
- activeTab(isRoute)
53
- }
54
- })
55
- const title = computed<string>(() => {
56
- return props.item.title || t('undefined')
57
- })
58
-
59
- const closeTab = () => {
60
- emit('close', props.item)
61
- }
62
- const activeTab = (isRoute: boolean = true) => {
63
- // if (!props.active) {
64
- emit('active', props.item, curtab, isRoute)
65
- // }
66
- }
67
- </script>
68
-
69
- <style lang="scss" scoped></style>
1
+ <template>
2
+ <li
3
+ ref="curtab"
4
+ class="stack-tab__item"
5
+ :class="{
6
+ 'is-active': item.active,
7
+ 'is-icon': item.closable
8
+ }"
9
+ @click="activeTab(true)"
10
+ >
11
+ <!-- <div v-if="!!icon" class="stack-tab__item-icon" :class="icon"></div>-->
12
+ <div class="stack-tab__item-title">
13
+ <div class="stack-tab__item-title-content" :title="title">
14
+ {{ title }}
15
+ </div>
16
+ </div>
17
+ <div
18
+ v-if="item.closable"
19
+ class="stack-tab__icon-close-fill stack-tab__item-button"
20
+ :title="t('VueStackTab.close')"
21
+ @click.stop="closeTab"
22
+ />
23
+ </li>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ import { computed, ref } from 'vue'
28
+ import type { ITabItem } from '@/lib/model/TabModel'
29
+ import { MittType, useEmitter } from '../../hooks/useTabMitt'
30
+ import { useI18n } from 'vue-i18n-lite'
31
+ // 消息
32
+ const emit = defineEmits(['close', 'active'])
33
+ const emitter = useEmitter()
34
+ const { t } = useI18n()
35
+ const curtab = ref<HTMLElement>()
36
+ const props = defineProps<{
37
+ item: ITabItem
38
+ }>()
39
+ /**
40
+ * 如果Active为true,就看看
41
+ */
42
+ // watch(
43
+ // () => props.item.active,
44
+ // (val) => {
45
+ // if (val) {
46
+ // activeTab()
47
+ // }
48
+ // }
49
+ // )
50
+ emitter.on(MittType.TAB_ACTIVE, ({ id, isRoute }: any) => {
51
+ if (props.item.id === id) {
52
+ activeTab(isRoute)
53
+ }
54
+ })
55
+ const title = computed<string>(() => {
56
+ return props.item.title || t('undefined')
57
+ })
58
+
59
+ const closeTab = () => {
60
+ emit('close', props.item)
61
+ }
62
+ const activeTab = (isRoute: boolean = true) => {
63
+ // if (!props.active) {
64
+ emit('active', props.item, curtab, isRoute)
65
+ // }
66
+ }
67
+ </script>
68
+
69
+ <style lang="scss" scoped></style>