效果实现图

文件结构布局

在这张图中,我们把页面分为了三个部分,分别是:
- 左侧的
Menu菜单 - 顶部的
NavBar - 中间的内容区
Main
本章中我们将会实现以下的核心解决方案:
- 用户退出方案
- 动态侧边栏方案
- 动态面包屑方案
除了这些核心内容之外,还有一些其他的小功能,比如:
- 退出的通用逻辑封装
- 伸缩侧边栏动画
vue3动画- 组件状态驱动的动态
CSS值等等
换句话而言,掌握了本章中的内容之后,后台项目的通用 Layout 处理,对于来说将变得小菜一碟!
1. 整个页面分为三部分,所以我们需要先去创建对应的三个组件:
layout/components/Sidebar/index.vuelayout/components/Navbar.vuelayout/components/AppMain.vue
2. 然后在 layout/index.vue 中引入这三个组件
vue
<script setup>
import Navbar from './components/Navbar'
import Sidebar from './components/Sidebar'
import AppMain from './components/AppMain'
</script>
3. 完成对应的布局结构
vue
<template>
<div class="app-wrapper">
<!-- 左侧 menu -->
<sidebar
id="guide-sidebar"
class="sidebar-container"
/>
<div class="main-container">
<div class="fixed-header">
<!-- 顶部的 navbar -->
<navbar />
</div>
<!-- 内容区 -->
<app-main />
</div>
</div>
</template>
4. 在 styles 中创建如下 css 文件:
variables.scss: 定义常量mixin.scss:定义通用的csssidebar.scss:处理menu菜单的样式
5. 为 variables.scss ,定义如下常量并进行导出( :export 可见 scss 与 js 共享变量):
scss
// sidebar
$menuText: #bfcbd9;
$menuActiveText: #ffffff;
$subMenuActiveText: #f4f4f5;
$menuBg: #304156;
$menuHover: #263445;
$subMenuBg: #1f2d3d;
$subMenuHover: #001528;
$sideBarWidth: 210px;
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
// JS 与 scss 共享变量,在 scss 中通过 :export 进行导出,在 js 中可通过 ESM 进行导入
:export {
menuText: $menuText;
menuActiveText: $menuActiveText;
subMenuActiveText: $subMenuActiveText;
menuBg: $menuBg;
menuHover: $menuHover;
subMenuBg: $subMenuBg;
subMenuHover: $subMenuHover;
sideBarWidth: $sideBarWidth;
}
6. 为 mixin.scss 定义如下样式:
scss
@mixin clearfix {
&:after {
content: '';
display: table;
clear: both;
}
}
@mixin scrollBar {
&::-webkit-scrollbar-track-piece {
background: #d3dce6;
}
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #99a9bf;
border-radius: 20px;
}
}
@mixin relative {
position: relative;
width: 100%;
height: 100%;
}
7. 为 sidebar.scss 定义如下样式:
scss
#app {
.main-container {
min-height: 100%;
transition: margin-left 0.28s;
margin-left: $sideBarWidth;
position: relative;
}
.sidebar-container {
transition: width 0.28s;
width: $sideBarWidth !important;
height: 100%;
position: fixed;
top: 0;
bottom: 0;
left: 0;
z-index: 1001;
overflow: hidden;
// 重置 element-plus 的css
.horizontal-collapse-transition {
transition: 0s width ease-in-out, 0s padding-left ease-in-out,
0s padding-right ease-in-out;
}
.scrollbar-wrapper {
overflow-x: hidden !important;
}
.el-scrollbar__bar.is-vertical {
right: 0px;
}
.el-scrollbar {
height: 100%;
}
&.has-logo {
.el-scrollbar {
height: calc(100% - 50px);
}
}
.is-horizontal {
display: none;
}
a {
display: inline-block;
width: 100%;
overflow: hidden;
}
.svg-icon {
margin-right: 16px;
}
.sub-el-icon {
margin-right: 12px;
margin-left: -2px;
}
.el-menu {
border: none;
height: 100%;
width: 100% !important;
}
.is-active > .el-submenu__title {
color: $subMenuActiveText !important;
}
& .nest-menu .el-submenu > .el-submenu__title,
& .el-submenu .el-menu-item {
min-width: $sideBarWidth !important;
}
}
.hideSidebar {
.sidebar-container {
width: 54px !important;
}
.main-container {
margin-left: 54px;
}
.submenu-title-noDropdown {
padding: 0 !important;
position: relative;
.el-tooltip {
padding: 0 !important;
.svg-icon {
margin-left: 20px;
}
.sub-el-icon {
margin-left: 19px;
}
}
}
.el-submenu {
overflow: hidden;
& > .el-submenu__title {
padding: 0 !important;
.svg-icon {
margin-left: 20px;
}
.sub-el-icon {
margin-left: 19px;
}
.el-submenu__icon-arrow {
display: none;
}
}
}
.el-menu--collapse {
.el-submenu {
& > .el-submenu__title {
& > span {
height: 0;
width: 0;
overflow: hidden;
visibility: hidden;
display: inline-block;
}
}
}
}
}
.el-menu--collapse .el-menu .el-submenu {
min-width: $sideBarWidth !important;
}
.withoutAnimation {
.main-container,
.sidebar-container {
transition: none;
}
}
}
.el-menu--vertical {
& > .el-menu {
.svg-icon {
margin-right: 16px;
}
.sub-el-icon {
margin-right: 12px;
margin-left: -2px;
}
}
// 菜单项过长时
> .el-menu--popup {
max-height: 100vh;
overflow-y: auto;
&::-webkit-scrollbar-track-piece {
background: #d3dce6;
}
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #99a9bf;
border-radius: 20px;
}
}
}
10. 因为将来要实现 主题更换 ,所以为 sidebar 赋值动态的背景颜色
xml
```vue
<template>
...
<!-- 左侧 menu -->
<sidebar
class="sidebar-container"
:style="{ backgroundColor: variables.menuBg }"
/>
...
</template>
<script setup>
import variables from '@/styles/variables.scss'
</script>
```
11. 为 Navbar、Sidebar、AppMain 组件进行初始化代码
xml
```vue
<template>
<div class="">{组件名}</div>
</template>
<script setup>
import {} from 'vue'
</script>
<style lang="scss" scoped></style>
```