Main.js:
<template>
<div id="app">
<el-container style="height: 100%;">
<el-header style="height: 80px; position: fixed; z-index: 1; width: 100%;" :style="topBg">
<Header />
</el-header>
<el-container style="padding-top: 80px; height: 100%;">
<el-aside width="auto" :style="leftBg">
<el-row class="tac">
<el-col :span="24">
<Nav />
</el-col>
</el-row>
</el-aside>
<el-main style="padding: 15px;">
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
import Header from "./layout/Header";
import Nav from "./layout/Nav";
export default {
name: "App",
data() {
return {
isCollapse: false,
leftBg: {
background: "#001529"
},
topBg: {
background: "#001529",
height: "80px",
fontSize: "32px",
color: "#ffffff"
}
};
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
}
},
components: {
Header,
Nav
}
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
height: 100%;
}
.el-header,
.el-footer {
background-color: #b3c0d1;
color: #333;
line-height: 80px;
}
.logo {
height: 80px;
line-height: 80px;
font-size: 30px;
font-family: "微软雅黑";
font-weight: bold;
text-shadow: 0 0 5px #000000;
display: flex;
align-items: center;
}
.logo img {
margin: 0 5px 0 0;
width: 35px;
height: 35px;
}
.el-aside {
background-color: #d3dce6;
color: #333;
}
.el-aside a {
text-decoration: none;
}
.el-menu {
background: none;
border-right: 0;
}
.el-submenu__title {
background: none !important;
}
.el-menu-item-group .el-menu-item {
padding-left: 52px !important;
}
.el-menu-item {
background: rgb(0, 21, 41) !important;
}
.el-menu-item.is-active {
color: #ffffff !important;
background: #1890ff !important;
}
.el-main {
background-color: #f0f2f5;
color: #333;
padding: 0;
}
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;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
</style>
Nav.vue:
<template>
<el-aside width="200px">
<el-menu
class="el-menu-vertical-demo"
background-color="rgb(0, 21, 41)"
text-color="#fff"
active-text-color="#ffd04b"
default-active="/main/data/tag"
:unique-opened="true"
@open="handleOpen"
@close="handleClose"
router
>
<NavItem
v-for="v in this.$router.options.routes[2].children"
:key="v.path"
:item="v"
:basePath="v.path"
/>
</el-menu>
</el-aside>
</template>
<script>
import NavItem from "./NavItem";
export default {
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
}
},
components: {
NavItem
}
};
</script>
<style scoped>
</style>
NavItem.vue:
<template>
<div>
<el-menu-item :index="basePath" v-if="!item.children">
<i :class="item.meta.icon"></i>
<span slot="title">{{item.meta.title}}</span>
</el-menu-item>
<el-submenu :index="basePath" v-else>
<template slot="title">
<i :class="item.meta.icon"></i>
<span>{{item.meta.title}}</span>
</template>
<NavItem v-for="child in item.children" :key="child.path" :item="child" :basePath="child.path" />
</el-submenu>
</div>
</template>
<script>
export default {
name: "NavItem",
data() {
return {};
},
props: ["item", "basePath"]
};
</script>
<style scoped>
.el-menu--collapse > div > .el-submenu > .el-submenu__title span {
height: 0;
width: 0;
overflow: hidden;
visibility: hidden;
display: inline-block;
}
.el-menu--collapse
> div
> .el-submenu
> .el-submenu__title
.el-submenu__icon-arrow {
display: none;
}
</style>
注意:
1、最外层div不可省略,否则鼠标在菜单项上移动时会报错;
2、<span slot="title"></span>不可省略,否则菜单收缩时鼠标放在菜单项上不会有文字标签链接;
Element-ui使用el-menu垂直布局递归生成菜单及菜单折叠后hover报错Maximum call stack size exceeded的解决方案_贵宾哥Cyril的博客-优快云博客
Header.js:
<template>
<el-row style="height: 80px;">
<el-col :span="6" class="logo">
<img :src="require('../../assets/logo.svg')" />VUE AntD管理系统
</el-col>
<el-col :span="4" style="padding-top: 10px;">
<el-radio-group v-model="isCollapse" style="margin-bottom: 20px;">
<el-radio-button :label="false">展开</el-radio-button>
<el-radio-button :label="true">收起</el-radio-button>
</el-radio-group>
</el-col>
<el-col :span="13" :offset="1">
<el-dropdown style="float: right;">
<span class="el-dropdown-link" style="color: #ffffff;">
user001
<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item icon="el-icon-edit">修改密码</el-dropdown-item>
<el-dropdown-item icon="el-icon-setting">设置默认密级</el-dropdown-item>
<el-dropdown-item icon="el-icon-circle-close" @click.native="loginout()">退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-col>
</el-row>
</template>
<script>
export default {
data() {
return {
isCollapse: false,
topBg: {
background: "#001529",
height: "80px",
fontSize: "32px",
color: "#ffffff"
}
};
}
};
</script>
<style scoped>
.logo {
height: 80px;
line-height: 80px;
font-size: 30px;
font-family: "微软雅黑";
font-weight: bold;
text-shadow: 0 0 5px #000000;
display: flex;
align-items: center;
}
.logo img {
margin: 0 5px 0 0;
width: 35px;
height: 35px;
}
</style>
router.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router);
let router = new Router({
mode: 'hash',
routes: [
{
path: '/',
name: 'index',
redirect: '/login'
},
{
path: '/login',
name: 'login',
component: () => import("@/pages/login/Index"),
meta: {
title: 'Login'
}
},
{
path: '/main',
alias: '/main',
name: 'main',
component: () => import("@/components/Main"),
meta: {
title: 'Main'
},
children: [
{
path: '/main/data',
alias: '/data',
name: 'data',
component: () => import("@/pages/statistics/Index"),
meta: {
title: '首页',
icon: 'el-icon-upload',
requireAuth: true
},
children: [
{
path: '/main/data/tag',
alias: '/tag',
name: 'tag',
component: () => import('@/pages/statistics/Tag'),
meta: {
title: '分析',
requireAuth: true
}
},
{
path: '/main/button',
alias: '/button',
name: 'button',
component: () => import('@/pages/statistics/StandardList'),
meta: {
title: '标准列表',
requireAuth: true
}
}
]
},
{
path: '/main/form',
alias: '/form',
name: 'form',
component: () => import('@/pages/form/Index'),
meta: {
title: '表单',
icon: 'el-icon-eleme',
requireAuth: true
},
children: [
{
path: '/main/form/validate',
alias: '/validate',
name: 'validate',
component: () => import('@/pages/form/Validate'),
meta: {
title: '基础表单',
requireAuth: true
}
},
{
path: '/main/form/step',
alias: '/step',
name: 'Step',
component: () => import('@/pages/form/step'),
meta: {
title: '分步表单',
requireAuth: true
}
},
{
path: '/main/form/senior',
alias: '/senior',
name: 'senior',
component: () => import('@/pages/form/senior'),
meta: {
title: '高级表单',
requireAuth: true
}
}
]
},
{
path: '/main/list',
alias: '/list',
name: 'list',
component: () => import('@/pages/list/Index'),
meta: {
title: '反馈',
icon: 'el-icon-upload',
requireAuth: true
},
children: [
{
path: '/main/list/card',
alias: '/card',
name: 'card',
component: () => import('@/pages/list/CardList'),
meta: {
title: '卡片列表',
requireAuth: true
}
}
]
},
{
path: '/main/dashbord',
alias: '/dashbord',
name: 'dashbord',
component: () => import('@/pages/dashbord/Index'),
meta: {
title: '分析',
icon: 'el-icon-upload',
requireAuth: true
},
children: [
{
path: '/main/dashbord/analysis',
alias: '/analysis',
name: 'analysis',
component: () => import('../pages/dashbord/analysis'),
meta: {
title: '分析页',
requireAuth: true
}
}
]
}
]
}
]
});
export default router
// router.beforeEach((to, from, next) => {
// let islogin = localStorage.getItem("islogin");
// islogin = Boolean(Number(islogin));
// if (to.path == "/login") {
// if (islogin) {
// next("/validate");
// } else {
// next();
// }
// } else {
// // requireAuth:可以在路由元信息指定哪些页面需要登录权限
// if (to.meta.requireAuth && islogin) {
// next();
// } else {
// next("/login");
// }
// }
// })
完整代码: