<script lang="ts" setup name="Topbar"> import { compile } from 'path-to-regexp' import Tools from '../Tools/index.vue' import useSettingsStore from '@/store/modules/settings' const route = useRoute() const settingsStore = useSettingsStore() const enableSubMenuCollapseButton = computed(() => { return settingsStore.mode === 'mobile' || ( ['side', 'head', 'single'].includes(settingsStore.menu.menuMode) && settingsStore.menu.enableSubMenuCollapseButton ) }) const breadcrumbList = computed(() => { const breadcrumbList = [] if (settingsStore.dashboard.enable) { breadcrumbList.push({ path: '/dashboard', title: settingsStore.dashboard.title, }) } if (route.meta.breadcrumbNeste) { breadcrumbList.push(...route.meta.breadcrumbNeste.filter(item => item.hide === false)) } return breadcrumbList }) const scrollTop = ref(0) onMounted(() => { window.addEventListener('scroll', onScroll) }) onUnmounted(() => { window.removeEventListener('scroll', onScroll) }) function onScroll() { scrollTop.value = document.documentElement.scrollTop || document.body.scrollTop } function pathCompile(path: string) { const toPath = compile(path) return toPath(route.params) } </script> <template> <div class="topbar-container" :class="{ fixed: settingsStore.topbar.fixed, shadow: scrollTop, }" data-fixed-calc-width > <div class="topbar-container-inner"> <div class="left-box"> <div v-if="enableSubMenuCollapseButton" class="sidebar-collapse" :class="{ 'is-collapse': settingsStore.menu.subMenuCollapse }" @click="settingsStore.toggleSidebarCollapse()"> <el-icon> <svg-icon name="toolbar-collapse" /> </el-icon> </div> <el-breadcrumb v-if="settingsStore.breadcrumb.enable && settingsStore.mode === 'pc' && settingsStore.app.routeBaseOn !== 'filesystem'"> <transition-group name="breadcrumb"> <el-breadcrumb-item v-for="(item, index) in breadcrumbList" :key="item.path" :to="index < breadcrumbList.length - 1 ? pathCompile(item.path) : ''"> {{ item.title }} </el-breadcrumb-item> </transition-group> </el-breadcrumb> </div> <tools /> </div> <img src="@/assets/images/header-image.png" class="img"> </div> </template> <style lang="scss" scoped> .topbar-container { position: absolute; z-index: 999; top: 0; display: flex; align-items: center; justify-content: space-between; height: var(--g-topbar-height); transition: width 0.3s, top 0.3s, transform 0.3s, background-color 0.3s, var(--el-transition-box-shadow); background-image: linear-gradient(90deg, #71b5ff 30%, #3d7eff); .topbar-container-inner { width: 100%; border-radius: 15px 10px 0 0; // background-color: var(--g-toolbar-bg); // background-color: #f1f2f6; display: flex; justify-content: space-between; } .img { height: 50px; position: absolute; z-index: -1; } &.fixed { position: fixed; &.shadow { box-shadow: 0 10px 10px -10px var(--g-box-shadow-color); } } .left-box { display: flex; align-items: center; padding-right: 50px; overflow: hidden; mask-image: linear-gradient(90deg, #000 0%, #000 calc(100% - 50px), transparent); .sidebar-collapse { display: flex; align-items: center; padding: 0 20px; height: 50px; cursor: pointer; .el-icon { color: var(--el-text-color-primary); transition: var(--el-transition-color), var(--el-transition-md-fade); } &:hover .el-icon { color: var(--el-color-primary); } &.is-collapse .el-icon { transform: rotateZ(-180deg); } & + .el-breadcrumb { margin-left: 0; } } :deep(.el-breadcrumb) { margin-left: 20px; white-space: nowrap; .el-breadcrumb__item { display: inline-block; float: none; span { font-weight: normal; } &:last-child span { color: #918f90; } } } } } // 面包屑动画 .breadcrumb-enter-active { transition: all 0.25s; } .breadcrumb-enter-from, .breadcrumb-leave-active { opacity: 0; transform: translateX(30px) skewX(-50deg); } </style>