index.vue 5.07 KB
<script lang="ts" setup name="SubSidebar">
import Logo from '../Logo/index.vue'
import SidebarItem from '../SidebarItem/index.vue'
import useSettingsStore from '@/store/modules/settings'
import useMenuStore from '@/store/modules/menu'
import { useRoute } from "vue-router";
const route = useRoute();

const settingsStore = useSettingsStore()
const menuStore = useMenuStore()

const sidebarScrollTop = ref(0)

function onSidebarScroll(e: Event) {
  sidebarScrollTop.value = (e.target as HTMLElement).scrollTop
}

/** 如果当前路由是下级,不在左侧导航菜单。通过找到它的上级,直到找出在左侧存在的。解决跳转后左侧菜单没有选中状态的问题。 */
const defaultMenuActive = computed(() => {
  let path = route.meta.activeMenu || route.path;
  let sideMenus = menuStore.sidebarMenus;
  let isSide = sideMenus.some(s => s.path === path || s.children?.some(c => path === `${s.path}/${c.path}`));
  if (isSide) {
    return path;
  }
  let matched = route.matched;
  if (matched.length > 1) {
    matched = matched.slice(0).reverse();
    for (const r of matched) {
      if (sideMenus.find(s => s.path === r.path || s.children?.some(c => r.path === `${s.path}/${c.path}`))) {
        return r.path;
      }
    }
  }
  return path;
});

</script>

<template>
  <div v-if="['side', 'head', 'single'].includes(settingsStore.settings.menu.menuMode) || settingsStore.mode === 'mobile'" class="sub-sidebar-container" :class="{ 'is-collapse': settingsStore.mode === 'pc' && (settingsStore.settings.menu.subMenuCollapse || defaultMenuActive =='/data-asset-index') }" @scroll="onSidebarScroll">
    <Logo
      :show-logo="settingsStore.settings.menu.menuMode === 'single'" class="sidebar-logo" :class="{
        'sidebar-logo-bg': settingsStore.settings.menu.menuMode === 'single',
        'shadow': sidebarScrollTop,
      }"
    />
    <!-- 侧边栏模式(无主导航) -->
    <el-menu
      :unique-opened="settingsStore.settings.menu.subMenuUniqueOpened" :default-openeds="menuStore.defaultOpenedPaths" :default-active="defaultMenuActive" :collapse="settingsStore.mode === 'pc' && (settingsStore.settings.menu.subMenuCollapse || defaultMenuActive =='/data-asset-index')" :collapse-transition="false" :class="{
        'is-collapse-without-logo': settingsStore.settings.menu.menuMode !== 'single' && settingsStore.settings.menu.subMenuCollapse,
      }"
    >
      <transition-group name="sub-sidebar">
        <template v-for="(route, index) in menuStore.sidebarMenus">
          <SidebarItem v-if="route.meta?.sidebar !== false" :key="route.path || index" :item="route" :base-path="route.path" />
        </template>
      </transition-group>
    </el-menu>
  </div>
</template>

<style lang="scss" scoped>
.sub-sidebar-container {
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;

  // firefox隐藏滚动条
  scrollbar-width: none;

  // chrome隐藏滚动条
  &::-webkit-scrollbar {
    display: none;
  }

  width: var(--g-sub-sidebar-width);
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  background-color: var(--g-sub-sidebar-bg);
  // box-shadow: 10px 0 10px -10px var(--g-box-shadow-color);
  // transition: background-color 0.3s, var(--el-transition-box-shadow), left 0.3s, width 0.3s;
  border-right: 1px solid #d9d9d9;
  transition: width 0.3s;

  &.is-collapse {
    display: none;
    width: 0;

    .sidebar-logo {
      &:not(.sidebar-logo-bg) {
        display: none;
      }

      :deep(span) {
        display: none;
      }
    }
  }

  .sidebar-logo {
    transition: box-shadow 0.2s, background-color 0.3s, color 0.3s;
    background-color: var(--g-sub-sidebar-bg);

    &:not(.sidebar-logo-bg) {
      :deep(span) {
        color: var(--g-sub-sidebar-menu-color);
      }
    }

    &.sidebar-logo-bg {
      background-color: var(--g-main-sidebar-bg);
    }

    &.shadow {
      box-shadow: 0 10px 10px -10px var(--g-box-shadow-color);
    }
  }

  .el-menu {
    border-right: 0;
    padding-top: var(--g-sidebar-logo-height);
    transition: border-color 0.3s, background-color 0.3s, color 0.3s, padding-top 0.3s;
    background-color: var(--g-sub-sidebar-bg);

    &:not(.el-menu--collapse) {
      width: inherit;
    }

    &.is-collapse-without-logo {
      padding-top: 0;
    }

    &.el-menu--collapse {
      :deep(.title-icon) {
        margin-right: 0;
      }

      :deep(.el-menu-item),
      :deep(.el-sub-menu__title) {
        span,
        .el-sub-menu__icon-arrow {
          display: none;
        }
      }
    }

    &.menu-radius:not(.el-menu--collapse) {
      .sidebar-item {
        padding: 0 10px;

        &:first-child {
          padding-top: 10px;
        }

        &:last-child {
          padding-bottom: 10px;
        }
      }

      :deep(.el-menu--inline),
      :deep(.el-menu-item),
      :deep(.el-sub-menu__title) {
        border-radius: 10px;
      }
    }
  }
}

// 次侧边栏动画
.sub-sidebar-enter-active {
  transition: opacity 0.3s, transform 0.3s;
}

.sub-sidebar-enter-from,
.sub-sidebar-leave-active {
  opacity: 0;
  transform: translateY(30px) skewY(10deg);
}

.sub-sidebar-leave-active {
  position: absolute;
}
</style>