1.布局
一個后臺的基本布局為
確定之后開始進行搭建。
這里是需要什么就填什么净嘀,所以以下步驟暫時沒有進排序。
創(chuàng)建src/layout/index.vue 文件
<template>
<!-- 整體頁面布局 -->
<el-row class="app-wrapper">
<el-container>
<!-- 側(cè)邊欄 -->
<el-aside width="220px">側(cè)邊欄</el-aside>
<el-container>
<!-- 頂部 -->
<el-header height="50px">header</el-header>
<!-- 主頁面 -->
<el-main>主頁面</el-main>
</el-container>
</el-container>
</el-row>
</template>
<script>
export default {
name: 'Layout'
}
</script>
<style lang="scss" scoped>
.app-wrapper {
position: relative;
height: 100%;
width: 100%;
}
</style>
由于樣式采用scss寫法侠讯。所以需要因為對應(yīng)的Loader支持
//package.json 生產(chǎn)包 加入
"devDependencies": {
...
"node-sass": "^4.12.0",
"sass-loader": "^8.0.2"
}
命令安裝
npm install // vscode 終端cmd 快捷 Ctrl + ~ 數(shù)字1旁邊那個
修改router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Layout from '@/layout'
const routes = [
{
path: '/',
component: Layout,
name: 'Home'
// component: () => import('@/views/home/index')
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
項目跑起來
npm run serve
接下來開始為布局添磚加瓦挖藏。
側(cè)邊欄(sidebar)
創(chuàng)建src/layout/components/Sidebar.vue
<template>
<div>
側(cè)邊欄
</div>
</template>
<script>
export default {
name: 'Sidebar'
}
</script>
src/layout/index.vue 引入
<template>
<!-- 整體頁面布局 -->
<el-row class="app-wrapper">
<el-container>
<!-- 側(cè)邊欄 -->
<el-aside width="220px">
<sidebar />
</el-aside>
<el-container>
<!-- 頂部 -->
<el-header height="50px">header</el-header>
<!-- 主頁面 -->
<el-main>主頁面</el-main>
</el-container>
</el-container>
</el-row>
</template>
<script>
import Sidebar from './components/Sidebar.vue'
export default {
name: 'Layout',
components: {
Sidebar
}
}
</script>
開始組建樣式。
創(chuàng)建src/styles 文件夾存放項目樣式文件
創(chuàng)建index.scss:項目全局樣式(通用樣式)厢漩,具有較高的優(yōu)先級
創(chuàng)建theme.scss:項目顏色樣式
index.scss
* {
margin: 0;
padding: 0;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
html {
height: 100%;
box-sizing: border-box;
}
body {
height: 100%;
// 字體抗鋸齒,使用后字體看起來會更清晰舒服
font-size: 14px;
color: #58666e;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微軟雅黑",Arial,sans-serif;
}
a,
a:focus,
a:hover {
cursor: pointer;
color: inherit;
text-decoration: none;
}
div:focus {
outline: none;
}
src/main.js 入口文件引入全局樣式
import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 路由
import store from './store' // vuex
// element 組件這里全部引入膜眠,也可定制按需引入,如只要button溜嗜、table等用到的組件
import ElementPlus from 'element-plus'
// 所有組件相關(guān)的樣式
import 'element-plus/lib/theme-chalk/index.css'
// 全局樣式
import '@/styles/index.scss'
// 掛載
createApp(App).use(store).use(router).use(ElementPlus).mount('#app')
theme.scss 項目主題色加入顏色變量控制宵膨。維護起來會很方便
// sidebar
// 文字
$menuText:#bfcbd9;
// 背景
$menuBg:#20222a;
// 激活的背景色
$menuActiveBg:#009688;
$subMenuActiveText:#fff;
$menuHover:#263445;
$subMenuBg:#1f2d3d;
$subMenuHover:#001528;
$sideBarWidth: 210px;
:export {
menuText: $menuText;
menuActiveBg: $menuActiveBg;
subMenuActiveText: $subMenuActiveText;
menuBg: $menuBg;
menuHover: $menuHover;
subMenuBg: $subMenuBg;
subMenuHover: $subMenuHover;
sideBarWidth: $sideBarWidth;
}
Sidebar.vue 內(nèi)容樣式填充。
el-*組件的參數(shù)含義可以前往官方文檔查看
<template>
<el-row class="slidebar">
<el-col class="sidebar-container">
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-openeds="['1','2']"
class="el-menu-vertical-demo"
:router="true"
:background-color="theme.menuBg"
:text-color="theme.menuText"
:active-text-color="theme.suMenuActiveText"
>
<el-submenu index="1" class="hide-tile">
<template #title>
<i class="el-icon-sunny" />
<span>父級菜單</span>
</template>
<el-menu-item index="#">子菜單1</el-menu-item>
<el-menu-item index="#">子菜單2</el-menu-item>
<!-- 菜單進行分組 -->
<el-menu-item-group title="分組名字" class="default-menu">
<el-menu-item index="#">分組里的菜單1</el-menu-item>
<el-menu-item index="#">分組里的菜單2</el-menu-item>
</el-menu-item-group>
</el-submenu>
<el-submenu index="2" class="hide-tile">
<template #title>
<i class="el-icon-sunny" />
<span>多級菜單</span>
</template>
<el-menu-item-group title="分組名稱" class="default-menu">
<el-submenu index="2-1">
<template #title>子菜單</template>
<el-menu-item index="2-1-1">2級菜單</el-menu-item>
</el-submenu>
<el-submenu index="2-2">
<template #title>子菜單</template>
<el-menu-item index="2-2-1">2級菜單</el-menu-item>
</el-submenu>
<el-submenu index="2-3">
<template #title>子菜單</template>
<el-menu-item index="2-3-1">2級菜單</el-menu-item>
</el-submenu>
<el-submenu index="2-4">
<template #title>子菜單</template>
<el-menu-item index="2-4-1">2級菜單</el-menu-item>
</el-submenu>
</el-menu-item-group>
</el-submenu>
</el-menu>
</el-scrollbar>
</el-col>
</el-row>
</template>
<script>
import theme from '@/styles/theme.scss'
import { mapGetters } from 'vuex'
export default {
name: 'Sidebar',
computed: {
...mapGetters([
'routes'
]),
theme() {
return theme
}
}
}
</script>
<style lang="scss">
// 這里是個人覆蓋的一些樣式炸宵,喜歡官方的就不用加了
@import '@/styles/theme.scss';
.slidebar { //外套一個slidebar類辟躏。聲明以下樣式僅限slidebar的組件生效
.sidebar-container {
transition: width 0.5s;
width: $sideBarWidth;
background-color: $menuBg;
height: 100%;
position: fixed;
font-size: 0px;
top: 0;
bottom: 0;
left: 0;
z-index: 1001;
overflow: hidden;
.el-menu-item.is-active {
color: $subMenuActiveText !important;;
background-color: $menuActiveBg !important;
}
.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;
}
.svg-icon {
margin-right: 16px;
}
.sub-el-icon {
margin-right: 12px;
margin-left: -2px;
}
.el-menu {
border: none;
height: 100%;
width: 100% !important;
}
// menu hover
.submenu-title-noDropdown,.el-submenu__title {
&:hover {
color: $subMenuActiveText !important;
background-color: $menuHover !important;
}
}
.el-submenu__title i{
color: $subMenuActiveText !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;
background-color: #191a23 !important;
&:hover {
color: $subMenuActiveText !important;
background-color: $subMenuHover !important;
}
}
& .el-submenu .el-menu-item.is-active{
color: $subMenuActiveText !important;;
background-color: $menuActiveBg !important;
}
}
}
</style>
運行 看看 目前的 搭建情況
npm run serve
以上為樣式的搭建土全。暫時沒有任何功能
菜單動態(tài)化
接下來讓菜單欄根據(jù)路由進行變化捎琐,
創(chuàng)建store/modules/routers.js 創(chuàng)建一個路由模塊管理路由信息的變動
import { routes } from '@/router'
const state = {
routers: [] // 路由數(shù)組,存放菜單欄的路由數(shù)據(jù)
}
const mutations = {
SET_ROUTERS: (state, routers) => {
state.routers = routers
}
}
// function getMenuList(routes) { }
const actions = {
getRouters({ commit }) {
return new Promise(resolve => {
// 處理路由信息
// const res = getMenuList(routes)
// 這里由于暫時還沒有對 路由進行 任何限制裹匙。
// 所以不需要加工過濾某些需要權(quán)限才能展示的路由
const res = routes
// 更新狀態(tài)
commit('SET_ROUTERS', res)
// 返回數(shù)據(jù)
resolve(res)
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
/store/getters.js 加入 routers
這里可能有些變量會同名瑞凑。可以改為自己理解的命名
const getters = {
name: state => state.app.name,
routers: state => state.routers.routers
}
export default getters
然后給src/router/index.js 加入兩個路由概页,用于測試
import { createRouter, createWebHistory } from 'vue-router'
import Layout from '@/layout'
export const routes = [ //這里需要導(dǎo)出籽御,vuex那需要獲取
{
path: '/',
component: Layout,
name: '主頁'
// component: () => import('@/views/home/index')
},
{
path: '/dog',
component: Layout,
name: '狗子世界',
// component: () => import('@/views/home/index')
children: [
{
path: '/erha',
name: '哈士奇',
component: () => import('@/views/home/index')
}
]
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
重構(gòu)Sidebar.vue 代碼。例子內(nèi)容可以保存
我們這里不需要多級目錄。
<template>
<el-row class="slidebar">
<el-col class="sidebar-container">
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
class="el-menu-vertical-demo"
:router="true"
:background-color="theme.menuBg"
:text-color="theme.menuText"
:active-text-color="theme.suMenuActiveText"
>
<div v-for="(item, i) in routers" :key="i">
<el-submenu v-if="item.children" :index="item.path" class="hide-tile">
<template #title>
<i class="el-icon-sunny" />
<span>{{ item.name }}</span>
</template>
<el-menu-item v-for="(children, index) in item.children" :key="index" :index="item.path + '/' +children.path">{{ children.name }}</el-menu-item>
</el-submenu>
<el-menu-item v-else :index="item.path">
<i class="el-icon-menu" />
<template #title>{{ item.name }}</template>
</el-menu-item>
</div>
</el-menu>
</el-scrollbar>
</el-col>
</el-row>
</template>
<script>
import theme from '@/styles/theme.scss'
import { mapGetters } from 'vuex'
export default {
name: 'Sidebar',
computed: {
...mapGetters([
'routers'
]),
theme() {
return theme
}
},
mounted() {
this.$store.dispatch('routers/getRouters')
console.log(this.routers)
}
}
</script>
...省略了樣式
附加一些側(cè)邊欄功能铃将。
根據(jù)路由激活菜單
// 加入 :default-active屬性
<el-menu
:default-active="getActive"
class="el-menu-vertical-demo"
:router="true"
:background-color="theme.menuBg"
:text-color="theme.menuText"
:active-text-color="theme.suMenuActiveText"
>
//script
computed: {
...mapGetters([
'routers'
]),
theme() {
return theme
},
getActive() {
// 根據(jù)當(dāng)前路由展示激活菜單。
const route = this.$route
const { meta, path } = route
if (meta.activeMenu) {
return meta.activeMenu
}
return path
}
},
增加抽屜效果
頂部加入按鈕哑梳。
<el-container>
<!-- 側(cè)邊欄 -->
<el-aside :width="open ? '210px' : '0px'">
<sidebar :open="open" />
</el-aside>
<el-container>
<!-- 頂部 -->
<el-header height="50px">
<div class="sidebar-switch" @click="open = !open">
<i :class="open ? 'el-icon-s-fold':'el-icon-s-unfold'" />
</div>
<el-col>header</el-col>
</el-header>
<!-- 主頁面 -->
<el-main>主頁面</el-main>
</el-container>
</el-container>
...樣式
<style lang="scss" scoped>
.app-wrapper {
position: relative;
height: 100%;
width: 100%;
.el-aside{
transition: .5s;
}
.sidebar-switch {
height: 100%;
width: 50px;
line-height: 50px;
cursor: pointer;
i {
font-size: 22px;
}
}
}
</style>
Sidebar.vue
...
<el-col class="sidebar-container" :style="`width:${open ? '210' : '0'}px;`">
...
//script
name: 'Sidebar',
props: {
open:{
type: Boolean,
default: true
}
},
computed: {
...