后台管理的模板很多,vue本身就提供了完整的vue-template-admin,vue-admin-beautiful等后台管理系统化框架,但是这些框架正是因为成体系而显得繁重。假如你想搭建一个静态的后台管理模板页面和几个单独的菜单页面,直接就上框架是否就有点大材小用了呢 百分之九十以上的后台管理布局基本都是头部导航,侧边栏,主内容三部分组成。所以,将其单独摘出来为一个单独的轻量后台页面就很有必要了。
1. 效果展示
最常见的系统布局就是:左右布局。左侧是菜单栏,右侧是内容区,内容区又分为头部和展示区。。所以我们的效果显示如下:
目录结构呢,也很简单,因为不涉及请求,所以就是vue+element+vuex即可
这种就很适合做vue的静态页面演示开发,因为就只有几个页面,不涉及复杂的路由和权限啥的。
本博文是借鉴了这篇博客写的:vue+elementUi——实现后台管理系统的布局(sideBar+header+appMain)_element ui页面布局模板-CSDN博客
但是由于它的细节问题太多,在调试过程中也遇到了一些问题,所以重新写一篇调试完后的代码,主要的就是方便你我他。
2.关键代码
如果迁入自由的项目,可以复制对应的关键代码,store代码,配置对应的路由,自己调试也可。如果想直接拿来即用的,下面也会附上vue代码git地址。
index.vue 主页面,负责引入头部,侧边栏,主内容组件
<template><div class="app-wrapper"><div class="layout-aside" :class="isCollapse?'collapse':''"><div class="layout-logo"><router-link to="/"><img v-show="!isCollapse" style="width:50px;height:auto" src="@/assets/logo.png" alt="logo"/><img v-show="isCollapse" style="width:44px;height:auto" src="@/assets/logo.png" alt="logo"/><!-- <span v-show="!isCollapse">工业品超市管理后台</span> --></router-link></div><SideBar :collapse="isCollapse" /></div><div class="layout-container" :class="{collapse:isCollapse}"><div class="layout-header" :class="{collapse:isCollapse}"><Header /></div><div class="layout-main"><AppMain /></div></div></div>
</template>
<script>import Header from "@/components/Header";import SideBar from "@/components/SideBar";import AppMain from "@/components/AppMain";export default{name:'layout',//此页面在router/index.js中对应的namecomponents:{Header,SideBar,AppMain},computed:{isCollapse:function(){return this.$store.state.isCollapse;}},methods:{}}
</script>
<style lang="scss" scoped>
.app-wrapper{position:relative;
}
.layout-aside{position:fixed;left:0;top:0;height:100vh;width:210px;transition:all 0.3s;background-color:#fff;.layout-logo{height:60px;background-color:#ffffff;a{display:flex;width:100%;height:60px;justify-content:center;align-items:center;}img{width:100px;height:auto;}}
}
.layout-aside.collapse{width:64px;
}
.layout-container{margin-left:210px;height:100%;overflow:hidden;
}
.layout-container.collapse{margin-left:64px;transition:all 0.1s;
}
.layout-header{position:fixed;z-index:1;top:0;right:0;width:calc(100% - 210px);height:60px;box-shadow:0 1px 3px rgba(0,21,41,0.08);background-color:#fff;
}
.layout-header.collapse{width:calc(100% - 64px);transition:all 0.1s;
}
.layout-main{padding: 20px;min-height:calc(100vh - 150px);margin:70px 15px 10px 10px;background-color:#fff;
}
</style>
Header头部部分:
<template><div class="header-wrapper"><div class="header-left"><div class="open-icon" @click="handleCollapse"><i class="el-icon-s-fold" v-show="!isMenuOpen"></i><i class="el-icon-s-unfold" v-show="isMenuOpen"></i><span style="font-size:16px;margin-left:5px">梦缘系统</span></div><el-breadcrumb separator="/"><template v-for="(item,index) in breadcrumbList"><el-breadcrumb-item :key="index" v-if="item.meta.title" :to="{path:item.path}"></el-breadcrumb-item></template></el-breadcrumb></div><div class="header-right"><span class="header-user">{{currentName}},欢迎回来</span><el-dropdown trigger="click"><span class="el-dropdown-line"><img src="https://liuqingwushui.top/usr/uploads/2024/10/09/1728443808722546.jpg" style="border-radius:50%;width:32px" alt="avatar"/><i class="el-icon-arrow-down el-icon--right"></i></span><el-dropdown-menu slot="dropdown"><el-dropdown-item icon="el-icon-setting">修改密码</el-dropdown-item ><el-dropdown-item icon="el-icon-guide" @click.native="handleLogout">退出登录</el-dropdown-item ></el-dropdown-menu></el-dropdown></div></div>
</template>
<script>// import {logout} from "@/api/user";export default{name:'Header',data(){return {isMenuOpen:false,breadcrumbList:[],currentName:'admin'}},watch:{$route(to,from){this.updateBreadcrumb(to.matched);}},mounted(){this.updateBreadcrumb(this.$route.matched);},methods:{updateBreadcrumb(list=[]){this.breadcrumbList = list;},handleCollapse(){this.isMenuOpen= !this.isMenuOpen;this.$store.commit('changeCollapse',this.isMenuOpen);},handleLogout(){this.$confirm('确认退出?','提示',{confirmButtonTextt:'确定',cancelButtonText:'取消',type:'warning'}).then(()=>{//logout();this.$router.push('/login');}).catch(()=>{})}}}
</script>
<style lang="scss" scope>
.header-wrapper{display:flex;justify-content:space-between;align-content:center;padding:0 15px;height:60px;.header-left{display:flex;align-items:center;.open-icon{font-size:20px;margin-right:15px;cursor:pointer;display: flex;align-items: center;}}.header-right{display:flex;align-items:center;.header-user{margin-right:15px;}}
}
.el-dropdown-link{cursor:pointer;color:#409eff;img{width:40px;height:40px;border-radius:5px;}
}
.el-icon-arrow-down{font-size:12px;
}
.demostration{display:block;color:#8492a6;font-size:14px;margin-bottom:20px;
}
</style>
Sidebar侧边栏部分:
<template><el-scrollbar class="sidebar-scroll"><el-menu class="el-menu-vertical-demo" :default-active="this.$route.path" :collapse="isCollapse" router><template v-for="(item,index) in menuData"><el-submenu v-if="item.children && item.children.length > 0" :key="index" :index="item.path"><template slot="title"><i :class="item.meta.icon"></i><span>{{ item.meta.title }}</span></template><el-menu-itemv-for="(child,childIndex) in item.children":key="`${index}-${childIndex}`":index="child.path"><i :class="child.meta.icon"></i><span>{{ child.meta.title }}</span></el-menu-item></el-submenu><el-menu-item v-else :key="index" :index="item.path"><i :class="item.meta.icon"></i><span>{{ item.meta.title }}</span></el-menu-item></template></el-menu></el-scrollbar>
</template>
<script>import {mapState,mapGetters} from "vuex";export default{name:'SideBar',computed:{...mapGetters(['firstMenu','subMenu','menuData']),isCollapse:function(){return this.$store.state.isCollapse;}},props:{collapse:{type:Boolean,default:false}},data(){return {currentRouter:''}},watch:{$route(to,from){this.currentRouter = to.path;}},mouted(){this.currentRouter = this.$route.path;},methods:{}}
</script>
<style lang="scss" scoped>.sidebar-scroll{height:calc(100% - 60px);}.sidebar{height:100%;text-align:left;border-right:none;}.el-menu-vertical-demo:not(.el-menu--collapse) {width: 210px;min-height: 400px;}
</style>
Appmain主内容部分:
<template><div class="app-main"><transition name="fade-transfrom" mode="out-in"><router-view /></transition></div>
</template>
<script>
export default{name:'AppMain'
}
</script>
<style lang="scss" scope>.app-main{width:100%;height:100%;}
</style>
Store状态管理js:
// src/store/index.js
import Vue from 'vue';
import Vuex from 'vuex';Vue.use(Vuex);export default new Vuex.Store({state:{isCollapse:false,menuData:[{path:'/dream/home',meta:{icon:'el-icon-data-line',title:'首页'}},{path:'/dream/2',meta:{icon:'el-icon-office-building',title:'梦缘'}},{path:'/dream/3',meta:{icon:'el-icon-place',title:'流情'}},{path:'/dream/4',meta:{icon:'el-icon-postcard',title:'日志'}},{path:'/dream/5',meta:{icon:'el-icon-pie-chart',title:'数据'},children:[{path:'/dream/6',meta:{icon:'el-icon-postcard',title:'数据1'}},] }]},mutations:{changeCollapse: (state,isCollapse) => {state.isCollapse = isCollapse},setMenuData(state,menuData){state.menuData = menuData;}},actions: {// 异步 actions},getters:{menuData(state,rootState){if(state.filterMenu){const {permissions,roles} = rootState.accout;return filterMenu(JSON.parse(JSON.stringfy(state.menuData)),permissions,roles)}return state.menuData;},firstMenu(state){const {menuData} = state;if(menuData.length>0&&!menuData[0].fullPath){formatFullPath(menuData);}return menuData.map(item=>{const menuItem = {...item};delete menuItem.children;return menuItem})},subMenu(state){const {menuData,activateFirst} = state;if(menuData.length>0&&!menuData[0].fullPath){formatFullPath(menuData);}const current = menuData.find(menu=>menu.fullPath== activatedFirst);return current && current.chilren||[]}},modules: {// 模块}
});
3.示例源码下载
git地址:vue-admin-static: vue+element后台管理极简版:头部和侧边导航栏,固定路由。适合写vue简单的静态演示,不适合做复杂系统开发