4-02:创建基于 Layout 的基础架构
在本小节我们需要创建基于 Layout 的基本架构布局,所以说会涉及到大量的 CSS 内容,这些 CSS 大部分都是比较基础的可复用的 CSS 样式,又因为量比较大,所以说我们不会在视频中把这些所有的 CSS 全部手敲一遍,而是从中间挑出一些比较重要的 Css 内容去进行手写和介绍。这是本小节中一个比较特殊的地方,先和大家进行一下明确。
那么明确好了之后,我们再来看一下我们 Layout 的基本布局结构:
我们知道,当登录完成之后,那么我们会进入到 Layout 页面,这个 Layout 页面组件位于 Layout/index.vue 中,所以说想要实现这样的结构,那么我们就需要到对应的 layout 组件中进行。
1. 整个页面分为三部分,所以我们需要先去创建对应的三个组件:
layout/components/Sidebar/index.vuelayout/components/Navbar.vuelayout/components/AppMain.vue
2. 然后在 layout/index.vue 中引入这三个组件
<script setup>
import Navbar from './components/Navbar'
import Sidebar from './components/Sidebar'
import AppMain from './components/AppMain'
</script>
3. 完成对应的布局结构
<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 共享变量):
// 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 定义如下样式:
@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 定义如下样式:
#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;
}
}
}
8. 在 index.scss 中按照顺序导入以上样式文件
@import './variables.scss';
@import './mixin.scss';
@import './sidebar.scss';
9. 在 layout/index.vue 中写入如下样式
<style lang="scss" scoped>
/*在 css 中我们需要使用 ~@ 并表示 src 目录 */
@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>
10. 因为将来要实现 主题更换,所以为 sidebar 赋值动态的背景颜色
<template>
...
<!-- 左侧 menu -->
<sidebar
class="sidebar-container"
:style="{ backgroundColor: variables.menuBg }"
/>
...
</template>
<script setup>
import variables from '@/styles/variables.scss'
</script>
11. 为 Navbar、Sidebar、AppMain 组件进行初始化代码
<template>
<div class="">{组件名}</div>
</template>
<script setup>
import {} from 'vue'
</script>
<style lang="scss" scoped></style>
12. 至此查看效果为
13. 可见 Navbar 与 AppMain 重叠
14. 为 AppMain 进行样式处理
<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>
15. 查看效果
在本章节中,我们写入了大量的代码,其中以
css 代码为主,因为其中的大量 css 都是可复用的,比如 sidebar.scss ,所以我们这里并没有进行手写。那么对于大家来说,这里的 css 代码也没有手写的必要,毕竟这些重复的体力活,是没有必要所有的事情都亲历亲为的。
那么下一章节中,我们就去实现一下 navbar 中的功能操作。