vue3-element-admin侧边栏折叠:菜单展开/收起动画

vue3-element-admin侧边栏折叠:菜单展开/收起动画

【免费下载链接】vue3-element-admin 基于 vue3 + vite4 + typescript + element-plus 构建的后台管理系统(配套接口文档和后端源码)。vue-element-admin 的 vue3 版本。 【免费下载链接】vue3-element-admin 项目地址: https://gitcode.com/GitHub_Trending/vue3/vue3-element-admin

你是否在使用后台管理系统时,遇到侧边栏折叠不流畅、菜单展开卡顿的问题?vue3-element-admin通过精心设计的动画机制,让侧边栏切换如丝般顺滑。本文将深入解析其实现原理,带你掌握菜单展开/收起动画的核心技术。

侧边栏折叠核心实现

侧边栏折叠功能的核心状态管理集中在src/store/modules/app-store.ts中,通过sidebar对象维护展开状态:

const sidebar = reactive({
  opened: sidebarStatus.value === SidebarStatus.OPENED,
  withoutAnimation: false,
});

切换逻辑通过toggleSidebar方法实现,同步更新本地存储的状态:

function toggleSidebar() {
  sidebar.opened = !sidebar.opened;
  sidebarStatus.value = sidebar.opened ? SidebarStatus.OPENED : SidebarStatus.CLOSED;
}

这个状态会传递给菜单组件src/layouts/components/Menu/BasicMenu.vue,通过collapse属性控制折叠状态:

<el-menu
  ref="menuRef"
  :default-active="activeMenuPath"
  :collapse="!appStore.sidebar.opened"
  :collapse-transition="false"
>

菜单组件结构设计

菜单组件采用递归结构设计,通过src/layouts/components/Menu/components/MenuItem.vue实现嵌套菜单渲染。组件根据路由配置自动判断渲染叶子节点或子菜单:

<!-- 叶子节点 -->
<el-menu-item
  :index="resolvePath(onlyOneChild.path)"
  :class="{ 'submenu-title-noDropdown': !isNest }"
>
  <MenuItemContent 
    :icon="onlyOneChild.meta.icon || item.meta?.icon"
    :title="onlyOneChild.meta.title"
  />
</el-menu-item>

<!-- 子菜单 -->
<el-sub-menu v-else :index="resolvePath(item.path)" :data-path="item.path" teleported>
  <template #title>
    <MenuItemContent :icon="item.meta.icon" :title="item.meta.title" />
  </template>
  
  <MenuItem
    v-for="child in item.children"
    :key="child.path"
    :item="child"
    :base-path="resolvePath(child.path)"
  />
</el-sub-menu>

这种设计使菜单能自适应任意层级的路由配置,同时保持代码的可维护性。

折叠动画实现原理

虽然Element Plus的el-menu组件内置了折叠动画,但项目中通过自定义CSS实现了更精细的过渡效果。在src/layouts/components/Menu/components/MenuItem.vue中定义了折叠状态下的样式:

.hideSidebar {
  .submenu-title-noDropdown {
    & > span {
      display: inline-block;
      visibility: hidden;
      width: 0;
      height: 0;
      overflow: hidden;
    }
  }
  
  .el-sub-menu {
    & > .el-sub-menu__title {
      .el-sub-menu__icon-arrow {
        display: none;
      }
    }
  }
}

当侧边栏折叠时,通过添加.hideSidebar类触发菜单文本和图标的过渡效果。虽然el-menucollapse-transition属性被禁用,但通过CSS过渡实现了更平滑的宽度变化:

.el-menu--collapse {
  width: $sidebar-width-collapsed;
  
  .el-sub-menu {
    & > .el-sub-menu__title > span {
      display: inline-block;
      visibility: hidden;
      width: 0;
      height: 0;
      overflow: hidden;
    }
  }
}

父菜单激活状态处理

为提升用户体验,系统实现了父菜单激活状态同步功能。当子菜单激活时,父菜单会自动显示激活样式。这一功能在src/layouts/components/Menu/BasicMenu.vue中通过updateParentMenuStyles方法实现:

function updateParentMenuStyles() {
  // 查找当前激活的菜单项
  const activeMenuItem = menuEl.querySelector(".el-menu-item.is-active");
  
  if (activeMenuItem) {
    // 向上查找父级 el-sub-menu 元素
    let parent = activeMenuItem.parentElement;
    while (parent && parent !== menuEl) {
      if (parent.classList.contains("el-sub-menu")) {
        parent.classList.add("has-active-child");
      }
      parent = parent.parentElement;
    }
  }
}

对应的样式定义在src/layouts/components/Menu/components/MenuItem.vue中:

.el-sub-menu {
  &.has-active-child > .el-sub-menu__title {
    color: var(--el-color-primary) !important;
    background-color: var(--el-color-primary-light-9) !important;
    
    .menu-icon {
      color: var(--el-color-primary) !important;
    }
  }
}

这种设计确保用户在深层菜单中也能清晰感知当前位置。

主题适配与样式优化

系统支持多种主题模式,菜单组件需要适配不同主题下的样式。在src/layouts/components/Menu/components/MenuItem.vue中定义了深色主题和蓝色侧边栏主题的适配样式:

// 深色主题适配
html.dark {
  .el-menu-item:hover {
    background-color: $menu-hover;
  }
  
  .el-sub-menu {
    &.has-active-child > .el-sub-menu__title {
      color: var(--el-color-primary-light-3) !important;
      background-color: rgba(64, 128, 255, 0.15) !important;
    }
  }
}

// 蓝色侧边栏主题适配
html.sidebar-color-blue {
  .el-menu-item:hover {
    background-color: $menu-hover;
  }
}

通过CSS变量和主题类名的组合,实现了不同主题下的视觉一致性。

动画优化与性能考量

为确保动画流畅性,系统采用了多项优化措施:

  1. 避免布局抖动:通过固定侧边栏宽度和使用visibility:hidden而非display:none实现平滑过渡
  2. 减少重绘:使用CSS变换和透明度动画而非宽度和高度变化
  3. 状态缓存:通过src/layouts/components/Menu/BasicMenu.vue中的expandedMenuIndexes缓存展开状态,避免重复计算
// 存储已展开的菜单项索引
const expandedMenuIndexes = ref<string[]>([]);

const onMenuOpen = (index: string) => {
  expandedMenuIndexes.value.push(index);
};

const onMenuClose = (index: string) => {
  expandedMenuIndexes.value = expandedMenuIndexes.value.filter((item) => item !== index);
};

这些优化确保了在复杂菜单结构下依然保持流畅的交互体验。

总结与使用建议

vue3-element-admin的侧边栏折叠功能通过状态管理、组件递归和CSS过渡的组合,实现了既美观又实用的菜单交互体验。核心要点包括:

  • 使用响应式状态管理折叠状态
  • 递归组件设计支持无限层级菜单
  • 自定义CSS动画实现平滑过渡
  • 父菜单激活状态同步提升可用性
  • 多主题适配保证视觉一致性

建议开发者在扩展菜单功能时:

  1. 保持路由配置与菜单组件的解耦
  2. 通过CSS变量而非硬编码实现样式定制
  3. 利用withoutAnimation属性优化初始加载性能
  4. 注意测试不同主题和屏幕尺寸下的表现

通过这些设计决策,vue3-element-admin提供了一个既灵活又高效的后台菜单解决方案,可根据实际项目需求轻松定制和扩展。

【免费下载链接】vue3-element-admin 基于 vue3 + vite4 + typescript + element-plus 构建的后台管理系统(配套接口文档和后端源码)。vue-element-admin 的 vue3 版本。 【免费下载链接】vue3-element-admin 项目地址: https://gitcode.com/GitHub_Trending/vue3/vue3-element-admin

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值