mirror of
https://github.com/fugary/simple-element-plus-template.git
synced 2026-02-22 22:27:00 +00:00
217 lines
5.6 KiB
Vue
217 lines
5.6 KiB
Vue
<script setup>
|
|
import { useTabsViewStore } from '@/stores/TabsViewStore'
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|
import { isString } from 'lodash-es'
|
|
import TabsViewItem from '@/components/common-tabs-view/tabs-view-item.vue'
|
|
import { toGetParams } from '@/utils'
|
|
import { isNestedRoute } from '@/route/RouteUtils'
|
|
import { useGetDerivedNamespace } from 'element-plus'
|
|
import Sortable from 'sortablejs'
|
|
|
|
const router = useRouter()
|
|
const route = useRoute()
|
|
const tabsViewStore = useTabsViewStore()
|
|
const tabRef = ref()
|
|
let sortable = null
|
|
watch(route, () => {
|
|
if (route.path) {
|
|
tabsViewStore.addHistoryTab(route)
|
|
tabsViewStore.currentTab = route.path
|
|
}
|
|
}, { immediate: true })
|
|
|
|
onMounted(() => {
|
|
if (!tabsViewStore.historyTabs.length) {
|
|
tabsViewStore.addHistoryTab(route)
|
|
}
|
|
tabsViewStore.currentTab = route.path
|
|
if (tabRef.value?.tabNavRef) {
|
|
const ns = useGetDerivedNamespace().value
|
|
const { tabListRef } = tabRef.value.tabNavRef
|
|
sortable = new Sortable(tabListRef, {
|
|
animation: 150,
|
|
draggable: `.${ns}-tabs__item`,
|
|
filter: '.is-disabled',
|
|
onEnd (event) {
|
|
const { oldIndex, newIndex } = event
|
|
tabsViewStore.reIndexHistoryTab(oldIndex, newIndex)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
const selectHistoryTab = path => {
|
|
const tab = isString(path) ? tabsViewStore.findHistoryTab(path) : path
|
|
if (tab) {
|
|
router.push(tab)
|
|
if (!isNestedRoute(tab)) {
|
|
tabsViewStore.addCachedTab(tab)
|
|
}
|
|
}
|
|
}
|
|
|
|
const removeHistoryTab = path => {
|
|
const lastTab = tabsViewStore.removeHistoryTab({ path })
|
|
if (lastTab) {
|
|
selectHistoryTab(lastTab)
|
|
}
|
|
}
|
|
|
|
const refreshHistoryTab = tab => {
|
|
const time = new Date().getTime()
|
|
const query = Object.assign({}, tab.query, { _t: time })
|
|
router.replace(`${tab.path}?${toGetParams(query)}`)
|
|
if (!isNestedRoute(tab)) {
|
|
tabsViewStore.addCachedTab(tab)
|
|
}
|
|
}
|
|
|
|
const removeOtherHistoryTabs = tab => {
|
|
tabsViewStore.removeOtherHistoryTabs(tab)
|
|
selectHistoryTab(tab.path)
|
|
}
|
|
|
|
const removeHistoryTabs = (tab, type) => {
|
|
tabsViewStore.removeHistoryTabs(tab, type)
|
|
selectHistoryTab(tab.path)
|
|
}
|
|
|
|
const tabItems = ref()
|
|
const onDropdownVisibleChange = (visible, tab) => {
|
|
if (visible) {
|
|
tabItems.value.forEach(({ dropdownRef }) => {
|
|
if (dropdownRef.id !== tab.path) {
|
|
dropdownRef.handleClose()
|
|
}
|
|
})
|
|
}
|
|
}
|
|
onBeforeUnmount(() => {
|
|
sortable?.destroy()
|
|
sortable = null
|
|
})
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<el-tabs
|
|
ref="tabRef"
|
|
v-bind="$attrs"
|
|
v-model="tabsViewStore.currentTab"
|
|
class="common-tabs"
|
|
type="card"
|
|
:closable="tabsViewStore.historyTabs.length>1"
|
|
@tab-change="selectHistoryTab"
|
|
@tab-remove="removeHistoryTab"
|
|
>
|
|
<tabs-view-item
|
|
v-for="item in tabsViewStore.historyTabs"
|
|
ref="tabItems"
|
|
:key="item.path"
|
|
:tab-item="item"
|
|
:label-config="item.labelConfig"
|
|
@refresh-history-tab="refreshHistoryTab"
|
|
@remove-other-history-tabs="removeOtherHistoryTabs"
|
|
@remove-history-tabs="removeHistoryTabs"
|
|
@on-dropdown-visible-change="onDropdownVisibleChange"
|
|
@remove-history-tab="removeHistoryTab"
|
|
/>
|
|
</el-tabs>
|
|
</template>
|
|
|
|
<style scoped>
|
|
:deep(.el-tabs__header) {
|
|
margin: 0;
|
|
border-bottom: 1px solid var(--el-border-color-light) !important;
|
|
position: relative;
|
|
}
|
|
|
|
:deep(.el-tabs__nav) {
|
|
border: 0 !important;
|
|
}
|
|
|
|
/* Allow pseudo-elements to overflow and cover the header border */
|
|
:deep(.el-tabs__nav-wrap),
|
|
:deep(.el-tabs__nav-scroll) {
|
|
overflow: visible !important;
|
|
}
|
|
|
|
:deep(.el-tabs__item) {
|
|
border: 1px solid transparent !important;
|
|
margin: 0 4px 0 0;
|
|
border-radius: 4px 4px 0 0;
|
|
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
|
/* Default inactive background */
|
|
background-color: var(--el-fill-color-light);
|
|
}
|
|
|
|
/* Bottom border for inactive tabs */
|
|
:deep(.el-tabs__item:not(.is-active)) {
|
|
border-bottom: 1px solid var(--el-border-color-light) !important;
|
|
}
|
|
|
|
/* Specific styling for active tab to look "connected" to content */
|
|
:deep(.el-tabs__item.is-active) {
|
|
background-color: var(--el-bg-color);
|
|
border-left: 1px solid var(--el-border-color-light) !important;
|
|
border-right: 1px solid var(--el-border-color-light) !important;
|
|
border-top: 1px solid var(--el-border-color-light) !important;
|
|
border-bottom: 1px solid transparent !important;
|
|
position: relative;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* Cover the header bottom border under active tab */
|
|
:deep(.el-tabs__item.is-active)::before {
|
|
content: "";
|
|
position: absolute;
|
|
bottom: -2px;
|
|
left: 0;
|
|
right: 0;
|
|
height: 4px;
|
|
background-color: var(--el-bg-color);
|
|
z-index: 10;
|
|
}
|
|
|
|
/* Top highlight line for active tab */
|
|
:deep(.el-tabs__item.is-active)::after {
|
|
content: "";
|
|
position: absolute;
|
|
top: -1px;
|
|
left: -1px;
|
|
width: calc(100% + 2px);
|
|
height: 2px;
|
|
background-color: var(--el-color-primary);
|
|
border-radius: 4px 4px 0 0;
|
|
}
|
|
|
|
:deep(.el-tabs__item:not(.is-active):hover) {
|
|
background-color: var(--el-fill-color);
|
|
color: var(--el-color-primary);
|
|
}
|
|
|
|
/* Dark mode adjustments */
|
|
.dark :deep(.el-tabs__header) {
|
|
border-bottom: 1px solid var(--el-border-color-darker) !important;
|
|
}
|
|
|
|
.dark :deep(.el-tabs__item) {
|
|
background-color: var(--el-bg-color-overlay);
|
|
}
|
|
|
|
.dark :deep(.el-tabs__item:not(.is-active)) {
|
|
border-bottom: 1px solid var(--el-border-color-darker) !important;
|
|
}
|
|
|
|
.dark :deep(.el-tabs__item.is-active) {
|
|
background-color: var(--el-bg-color);
|
|
border-color: var(--el-border-color-darker) !important;
|
|
border-bottom-color: transparent !important;
|
|
}
|
|
|
|
.dark :deep(.el-tabs__item.is-active)::before {
|
|
background-color: var(--el-bg-color);
|
|
}
|
|
</style>
|