这里我使用的路由嵌套解决方案
page.vue
<template>
<div class="home">
<el-container>
<el-menu
:default-active="this.$route.path"
class="el-menu-vertical-demo"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
@open="handleOpen"
@close="handleClose"
:collapse="isCollapse"
>
<!--logo-->
<el-submenu class="logo-min" index="1">
<template slot="title">
<i v-show="isCollapse" class="el-icon-setting"></i>
<el-image class="logo" v-show="!isCollapse" :src="logo" fit="contain"></el-image>
</template>
<el-menu-item-group>
<span slot="title">超级管理员</span>
<el-menu-item index="#">个人资料</el-menu-item>
<el-menu-item index="#">联系我们</el-menu-item>
<el-menu-item index="#" @click="handleCommand">安全退出</el-menu-item>
</el-menu-item-group>
</el-submenu>
<!--动态菜单-->
<el-submenu v-for="(item, i) in navList" :key="i" :index="item.id">
<template slot="title">
<i :class="item.icon"></i>
<span slot="title">{{ item.name }}</span>
</template>
<el-menu-item-group v-for="(ite, i) in item.son" :key="i">
<el-menu-item @click="handleLink({ name: ite.name, path: ite.path,id: ite.id })" :index="ite.path">{{ ite.name }}</el-menu-item>
</el-menu-item-group>
</el-submenu>
</el-menu>
<!--右侧-->
<el-container>
<!--导航-->
<el-header class="head">
<el-radio-group class="isCollapse" v-model="isCollapse">
<el-radio-button v-show="isCollapse" :label="false"><i class="el-icon-s-unfold"></i></el-radio-button>
<el-radio-button v-show="!isCollapse" :label="true"><i class="el-icon-s-fold"></i></el-radio-button>
</el-radio-group>
<el-tabs v-model="editableTabsValue" type="card" closable @tab-remove="removeTab" @tab-click="link">
<el-tab-pane v-for="item in editableTabs" :key="item.index" :label="item.name" :name="item.path"></el-tab-pane>
</el-tabs>
</el-header>
<!--内容-->
<el-main><router-view /></el-main>
<el-footer>Author:liming 版本:1.0.1 版权所有:创新工场</el-footer>
</el-container>
</el-container>
</div>
</template>
<script>
// @ is an alias to /src
import logo from '../../assets/admin_logo.png';
//import { getListAPI } from '../../api/api.js';
export default {
computed: {
key() {
return this.$route.path;
}
},
data() {
return {
logo: logo,
isCollapse: false,
iconHid: false,
navList: [
{
id: '2',
name: '商品',
icon: 'el-icon-location',
path: '',
son: [
{
id: '4',
number: '2-1',
name: '商品管理',
icon: '',
path: '/about'
},
{
id: '5',
number: '2-2',
name: '商品分类',
icon: '',
path: '2'
},
{
id: '6',
number: '2-3',
name: '商品规格',
icon: '',
path: '3'
},
{
id: '7',
number: '2-4',
name: '商品评价',
icon: '',
path: '4'
}
]
},
{
id: '3',
name: '会员',
icon: 'el-icon-document',
path: '',
son: [
{
id: '8',
number: '3-1',
name: '会员管理',
icon: '',
path: '/list'
},
{
id: '9',
number: '3-2',
name: '会员等级',
icon: '',
path: '5'
},
{
id: '10',
number: '3-3',
name: '会员分组',
icon: '',
path: '6'
},
{
id: '11',
number: '3-3',
name: '抽奖列表',
icon: '',
path: '7'
}
]
}
],
editableTabsValue: '商品管理',
editableTabs: [],
};
},
methods: {
onSubmit() {
console.log('submit!');
},
handleOpen(key, keyPath) {
console.log(key);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
},
handleLink(data) {
this.addTab(data);
},
/**
* 注销
*/
handleCommand() {
localStorage.removeItem('Authorization');
localStorage.removeItem('refresh_token');
localStorage.removeItem('appId');
console.log(localStorage.getItem('Authorization'));
this.$router.go(0);
},
/**
* 添加tab
* @param {Object} targetName
*
*
*/
addTab(targetName) {
let that = this;
that.editableTabs.push(targetName);
// 数组去重
let hash = {};
that.editableTabs = that.editableTabs.reduce((item, next) => {
if (hash[next.name] ? '' : hash[next.name] = true) {
item.push(next);
}
return item;
}, []);
if(that.editableTabsValue!=targetName.path){
that.$router.push({path:targetName.path})
that.editableTabsValue = targetName.path;
}
},
/**
* 删除tab
* @param {Object} targetName
*/
removeTab(targetName) {
let tabs = this.editableTabs;
let activeName = this.editableTabsValue;
if (activeName === targetName) {
tabs.forEach((tab, index) => {
if (tab.path === targetName) {
let nextTab = tabs[index + 1] || tabs[index - 1];
if (nextTab) {
activeName = nextTab.name;
}
}
});
}
this.editableTabsValue = targetName;
this.editableTabs = tabs.filter(tab => tab.path !== targetName);
},
/**
* 点击切换路由
* @param {Object} tab
*
*/
link(tab) {
this.$router.push(tab.name);
}
}
};
</script>
<style>
.home {
height: 100%;
}
.el-container {
height: 100%;
}
.el-header,
.el-footer {
color: #333;
text-align: center;
line-height: 3rem;
}
.head {
height: 3rem !important;
}
.el-aside {
background-color: #304156;
color: #fff;
text-align: center;
height: 100%;
}
.el-main {
background-color: #e9eef3;
color: #333;
text-align: center;
line-height: 160px;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
.el-menu-item {
overflow: hidden;
}
.logo-min {
overflow: hidden;
}
.logo-min .el-icon-arrow-down {
display: none;
}
.logo {
width: 88%;
margin: 0.5rem 6%;
}
.user {
padding-left: 20px;
}
.user span {
color: #c0c4cc;
}
.isCollapse {
float: left;
}
.isCollapse span {
background: none;
border: none !important;
padding: 12px 0;
}
.isCollapse i {
font-size: 1.3rem;
}
</style>
router/index
{
path: '/',
name: 'Page',
component: Page,
children: [{
path: 'about', //以“/”开头的嵌套路径会被当作根路径,所以子路由上不用加“/”;在生成路由时,主路由上的path会被自动添加到子路由之前,所以子路由上的path不用在重新声明主路由上的path了。
name: 'About',
component: () => import( /* webpackChunkName: "about" */ '../views/About.vue')
},
{
path: 'list', //以“/”开头的嵌套路径会被当作根路径,所以子路由上不用加“/”;在生成路由时,主路由上的path会被自动添加到子路由之前,所以子路由上的path不用在重新声明主路由上的path了。
name: 'List',
component: () => import( /* webpackChunkName: "about" */ '../views/List.vue')
},
]
},
文件结构
image.png
about 页面示例
image.png