携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情
搭建Layout架构 解决方案与实现
到此,我们已经实现了登录相关的内容,下边我们就来看看登录后要做些什么
登录后,我们跳转的是 Layout 页面,那么我们就先来看看什么是 Layout 架构
简单来说,我们把 Layout 架构分成了三部分,分别是:
1、左侧的 Menu 菜单
2、顶部的 Navbar
3、中间的内容区 Main
了解了这些,我们就来看一看代码的实现
创建基于 Layout 的基础架构
当登录完成之后,那么我们会进入到 Layout 页面,所以说想要实现这样的结构,那么我们就需要到对应的 layout 组件中进行
- 由于这个页面分为三个部分,所以我们需要创建对应的三个组件
1、layout/components/SideBar/index.vue
2、layout/components/NavBar/index.vue
3、layout/components/AppMain/index.vue
- 在
layout/index.vue中引入他们
<script setup>
import Navbar from './components/NavBar'
import Sidebar from './components/SideBar'
import AppMain from './components/AppMain'
</script>
- 在
layout/index.vue中完成对应的布局
<template>
<div class="app-wrapper">
<!-- 左侧 menu -->
<SideBar
id="guide-sidebar"
class="sidebar-container"
></SideBar>
<div class="main-container">
<div class="fixed-header">
<!-- 顶部的 navbar -->
<Navbar></Navbar>
</div>
<!-- 内容区 -->
<AppMain></AppMain>
</div>
</div>
</template>
- 在
styles中创建如下css文件
1、variables.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;
}
2、mixin.scss:定义通用的 css
@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%;
}
3、sidebar.scss:处理 menu 菜单的样式
#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;
}
}
}
- 在
index.scss中引入他们
@import './variables.scss';
@import './mixin.scss';
@import './sidebar.scss';
- 在
layout/index.vue中增加样式
<style lang="scss" scoped>
@import '~@/styles/mixin.scss';
@import '~@/styles/variables.scss';
.app-wrapper {
@include clearfix;
position: relative;
height: 100%;
width: 100%;
}
.fixed-header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: calc(100% - #{$sideBarWidth});
}
</style>
- 因为将来要实现主题更换,所以为
sidebar赋值动态的背景颜色
<template>
<!-- 左侧 menu -->
<SideBar
class="sidebar-container"
:style="{ backgroundColor: variables.menuBg }"
></SideBar>
</template>
<script setup>
import variables from '@/styles/variables.scss'
</script>
- 为
Navbar、Sidebar、AppMain组件进行初始化
<template>
<div class="">123</div>
</template>
<script setup>
import {} from 'vue'
</script>
<style lang="scss" scoped></style>
- 为
AppMain/index.vue进行样式处理
<template>
<div class="app-main">AppMain</div>
</template>
<script setup>
import {} from 'vue'
</script>
<style lang="scss" scoped>
.app-main {
min-height: calc(100vh - 50px);
width: 100%;
position: relative;
overflow: hidden;
padding: 61px 20px 20px 20px;
box-sizing: border-box;
}
</style>
此时 Layout 页面的布局已经完成了