一、页面主体框架构造
整体页面采用elementui的Container 布局容器,左侧导航栏采用elementui的NavMenu 导航菜单, 右侧主体界面采用elementui多Tabs 标签页展示, 顶栏容器的话使用我们自己编写的vue组件。
实现功能:
- 1.导航栏收缩功能
- 2.点击左侧导航栏右侧出现对呀tabs标签页
- 3.tabs标签页删除跳转到前一个页面
- 4最后一个tabs标签页不可删除
二、代码
- Adminindex.vue(主体框架)
<template>
<el-container>
<el-header height="40px"><indexheader></indexheader></el-header>
<el-container>
<el-aside width="200"><indexaside></indexaside></el-aside>
<el-main>
<indextab></indextab>
<router-view></router-view>
</el-main>
<!-- <el-footer height="50px">
<p>2021@zly ♥ yangyun 1314</p>
</el-footer> -->
</el-container>
</el-container>
</template>
<script>
import indexaside from '../components/Indexcomponents/asidecomponents'
import indexheader from '../components/Indexcomponents/headercomponents'
import indextab from '../components/Indexcomponents/tabscompontents'
export default {
name:'AdminIndex',
components:{
indexaside,
indexheader,
indextab
},
}
</script>
<style>
.el-header{
background-color: #7aaef1;
color: rgb(248, 247, 247);
text-align: center;
}
/* .el-footer{
background-color: #7aaef1;
color: rgb(248, 247, 247);
text-align: center;
} */
.el-aside {
background-color: #084B8A;
color: rgb(252, 247, 247);
text-align: center;
height: 680px;
}
.el-main {
background-color: #E9EEF3;
color: #333;
text-align: center;
padding: 0%;
margin: 0%;
/* line-height: 160px; */
}
body > .el-container {
margin-bottom: 40px;
}
.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
line-height: 260px;
}
.el-container:nth-child(7) .el-aside {
line-height: 320px;
}
</style>
- headercomponents.vue(头部组件)
<template>
<div class="header-main">
<div class="header-logo" @click="updateiscollapse()">
<h4>后台管理系统</h4>
</div>
<div class="header-user">
<div class="header-img">
<el-dropdown>
<div class="user-name"><h4>user</h4></div>
<div class="user-img">
<span class="el-dropdown-link">
<el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" style=""></el-avatar>
</span>
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>个人中心</el-dropdown-item>
<el-dropdown-item>退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</div>
</template>
<script>
export default {
name:'indexheader',
data(){
return{
isCollapse:'',
}
},
methods:{
// 展开收缩侧边导航栏
updateiscollapse(){
const isCollapse = this.$store.state.isCollapse
if(isCollapse === false){
const index = true
this.$store.dispatch('updateisCollapse', index)
}else if(isCollapse === true){
const index = false
this.$store.dispatch('updateisCollapse', index)
}else{
return
}
}
}
}
</script>
<style scoped>
.header-main{
height: 35px;
width: 1500px;
/* border: 1px solid blue; */
}
.header-logo{
float: left;
width: 175px;
height: 35px;
line-height: 2px;
cursor:default
/* text-align: center; */
/* border: 1px solid blue; */
}
.user-name{
float: right;
width: 50px;
height: 35px;
/* border: rgb(24, 245, 215) 1px solid; */
}
.user-img{
float:right;
}
.header-img{
float: right;
width: 120px;
height: 35px;
/* border: rgb(161, 209, 30) 1px solid; */
}
</style>
- asidecomponents.vue(左侧侧边栏组件)
<template>
<div class="aside-main">
<!-- <div class="header-zhankai">
<el-button icon="el-icon-s-fold" size="small" style="margin-top:6px;color: #7aaef1" v-if="this.type == '关闭'"></el-button>
<el-button icon="el-icon-s-unfold" size="small" style="margin-top:6px;" v-else-if="this.type == '打开'"></el-button>
</div> -->
<el-menu
class="el-menu-vertical-demo"
:default-active="defaultindex"
unique-opened
router
:collapse="isCollapse"
background-color="#084B8A"
text-color="#fff"
active-text-color="#ffd04b">
<!-- <router-link to="" v-trigger> -->
<el-menu-item index="/index/SystemHome" @click="getindexmenu($event)" v-trigger>
<i class="el-icon-s-home" style="color: #FFFFFF"></i>
<span slot="title">主页</span>
</el-menu-item>
<!-- </router-link> -->
<el-submenu v-for="item in menu" :key="item.index" :index="item.index">
<template slot="title">
<i class="el-icon-notebook-1" style="color: #FFFFFF"></i>
<span>{{item.name}}</span>
</template>
<el-submenu v-for="item1 in item.children" :key="item1.index" :index="item1.index">
<template slot="title">
<i class="el-icon-notebook-2" style="color: #FFFFFF"></i>
<span>{{item1.name}}</span>
</template>
<el-menu-item
v-for="item2 in item1.children"
:key="item2.index"
:index="item2.index"
@click="getmenu($event)"
>{{item2.name}}</el-menu-item>
</el-submenu>
</el-submenu>
</el-menu>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
data(){
return{
indexmenu:[
{
index:'/index/SystemHome',
name:'主页'
},
],
menu:[
{
index:'2',
name:'报表',
children:[
{
index:'3',
name:'人事报表',
children:[
{
index:'/index/RecruitmentManagement',
name:'招聘管理',
},
{
index:'/index/PersonnelFiles',
name:'人员档案'
}
]
}
]
}]
}
},
computed:{
...mapState(['defaultindex']),
...mapState(['isCollapse']),
},
methods:{
getindexmenu(e){
let index = e.index
let name = ''
// console.log(this.defaultactive);
for(const item in this.indexmenu){
if(this.indexmenu[item].index === index){
name = this.indexmenu[item].name
}
}
this.$store.dispatch('savemenuPath', [index,name]);
},
getmenu(e){
let index = e.index
let name = ''
for(const item in this.menu){
// console.log(this.menu[item].name);
if(this.menu[item].index === index){
name = this.menu[item].name
}else{
for(const item1 in this.menu[item].children){
// console.log(this.menu[item].children[item1].name);
if(this.menu[item].children[item1].index === index){
name = this.menu[item].children[item1].name
}else{
for(const item2 in this.menu[item].children[item1].children){
if(this.menu[item].children[item1].children[item2].index === index){
name = this.menu[item].children[item1].children[item2].name
}
}
}
}
}
}
this.$store.dispatch('savemenuPath', [index,name]);
}
},
directives:{
trigger:{
inserted(el,binging){
// console.log("自动触发事件")
el.click()
}
}
},
}
</script>
<style scoped>
a {
text-decoration: none;
}
.router-link-active {
text-decoration: none;
}
.aside-main{
text-align: left;
}
</style>
<style>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
</style>
- tabscomponents.vue(主题界面tabs标签)
<template>
<div class="app-tag">
<el-tag
closable
size="small"
v-for="(tag,index) in tagsname"
:key="tag.name"
type="success"
effect="dark"
:disable-transitions="true"
@close="handleClose(index)"
@click="handleClick(index)">
{{tag}}
</el-tag>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
name:'indextab',
data(){
return{
tagsname:[],
tagsindex:[],
name:'',
path:''
}
},
methods:{
handleClick(index){
// console.log(index);
// console.log(this.tagsindex[index]);
this.$store.dispatch('updatemenuactive', this.tagsindex[index])
this.$router.push(this.tagsindex[index])
},
handleClose(index){
// console.log(index);
if (this.tagsindex.length === 1) { // 如果只有一个标签则不能关闭
return
}
this.$store.dispatch('deletemenuPath', index);
this.$store.dispatch('updatemenuactive', this.tagsindex[index-1])
this.$router.push(this.tagsindex[index-1])
// this.$router.push(this.tagsindex[index-1])
}
},
computed:{
...mapState(['menuindex']),
...mapState(['menuname']),
},
watch: {
menuindex(index) {
// 监听mapState中的变量,当数据变化(有值、值改变等),
// 保证能拿到完整的数据,不至于存在初始化没有数据的问题,然后可以赋给本组件data中的变量
this.path = index;
this.tagsindex = this.path
// console.log(this.path);
},
menuname(name) {
this.name = name
this.tagsname = this.name
// console.log(this.name);
}
}
}
</script>
<style>
.app-tag{
padding: 0%;
margin: 0%;
height: 28px;
cursor:pointer;
/* background-color: #81DAF5; */
border: 1px solid #81DAF5;
}
.el-tag.el-tag--success.el-tag--small.el-tag--dark{
float: left;
/* margin-left: 2px; */
margin: 2px;
}
.tag-main{
padding: 0%;
border: 1px solid #81DAF5;
height: 100px;
}
</style>
- router/index.js (路由文件)
import Vue from 'vue'
import Router from 'vue-router'
import AdminIndex from '@/components/AdminIndex'
import AdminLogin from '@/components/AdminLogin'
import SystemHome from '@/components/SystemHome'
import RecruitmentManagement from '@/components/RecruitmentManagement'
import PersonnelFiles from '@/components/PersonnelFiles'
Vue.use(Router)
//获取原型对象上的push函数
const originalPush = Router.prototype.push
Router.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
};
export default new Router({
mode: 'history',
routes: [
{
path: '/',
redirect:'/login'
},
{
path: '/login',
name: 'AdminLogin',
component: AdminLogin,
},
{
path: '/index',
name: 'adminindex',
component: AdminIndex,
children: [
{
path: 'SystemHome', // 系统主页
name: 'SystemHome',
component :SystemHome
},
{
path: 'RecruitmentManagement', // 招聘管理
name: 'RecruitmentManagement',
component: RecruitmentManagement
},
{
path: 'PersonnelFiles', //人员档案
name: 'PersonnelFiles',
component: PersonnelFiles
},
]
},
]
})
- store/state.js(vuex state 数据存放文件)
export default {
menuindex:[], // 当前所有激活路由
menuname:[], // 当前所有激活菜单
defaultindex:'/index/SystemHome', // 当前菜单活动项/默认为首页
isCollapse: false // 当前菜单栏展开的状态
}
- store/actions.js(vuex actions文件)
// 触发保存菜单栏的路径方法
export const savemenuPath = ({ commit }, payload) => {
commit('savemenuPath', payload);
};
// 触发删除tabs标签页的方法
export const deletemenuPath = ({ commit }, payload) => {
commit('deletemenuPath', payload);
}
// 变更当前菜单活动项
export const updatemenuactive = ({ commit }, payload) => {
commit('updatemenuactive', payload)
}
// 判断当前菜单栏是否展开
export const updateisCollapse = ({ commit }, payload) =>{
commit('updateisCollapse', payload)
}
- store/mutations.js(vuex mutations文件)
import state from "./state";
// 保存当前菜单栏的路径及名称
export const savemenuPath = (state, name_index_arr) => {
state.defaultindex = name_index_arr[0]
if (state.menuindex.includes(name_index_arr[0])) {
return(true)
}else{
state.menuindex.push(name_index_arr[0]);
}
if (state.menuname.includes(name_index_arr[1])){
return(true)
}else{
state.menuname.push(name_index_arr[1]);
}
};
// 点击tabs标签页删除键时删除vuex数据
export const deletemenuPath = (state, index) =>{
state.menuindex.splice(index, 1)
state.menuname.splice(index, 1)
}
//变更当前菜单活动项
export const updatemenuactive = (state, index) =>{
state.defaultindex = index
}
//判断菜单栏是否展开
export const updateisCollapse = (state, index) =>{
state.isCollapse = index
}
- main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store/index';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.config.productionTip = false
Vue.use(ElementUI);
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})