效果图:
话不多说上代码
一、vue页面
home页代码
<template>
<div>
<el-container>
<el-aside width="collapse ? 200px : 35px">
<el-menu
:collapse="collapse"
:default-active="this.$store.state.title"
class="el-menu-vertical-demo"
unique-opened
active-text-color="#ffd04b"
text-color="#fff"
background-color="transparent"
@select="hh"
>
<el-button @click="collapseToggle" style="margin-top: 10px; margin-bottom: 10px">
<i class="el-icon-s-unfold" v-if="collapse" />
<i class="el-icon-s-fold" v-else />
</el-button>
<leftMenu :dataToSon="this.$store.state.tree" />
</el-menu>
</el-aside>
<el-container>
<el-header class="header">Header</el-header>
<el-main>
<multipleTabs></multipleTabs>
</el-main>
<el-footer>Footer</el-footer>
</el-container>
</el-container>
</div>
</template>
<script>
import leftMenu from '@/views/home/leftMenu'
import multipleTabs from '@/views/home/multipleTabs'
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'home',
components: {
leftMenu,
multipleTabs
},
data () {
return {
collapse: false
}
},
mounted () {
},
methods: {
hh (e) {
this.$store.commit('tab', e)
},
collapseToggle () {
this.collapse = !this.collapse
}
}
}
</script>
<style scoped>
.el-header, .el-footer {
background: url("../../../src/assets/111.jpg");
color: #333;
text-align: center;
}
.el-aside {
text-align: center;
}
.el-main {
color: #333;
text-align: center;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
min-width: 200px;
height: 100vh;
}
>>> .el-menu--collapse .menu {
display: none;
}
>>> .el-menu--collapse .el-submenu__icon-arrow {
display: none;
}
span {
display: none;
}
.el-menu-vertical-demo {
background: url("../../../src/assets/111.jpg");
height: 100vh;
border-right: 0;
}
</style>
leftMenu.vue代码
<template>
<div>
<fragment v-for="(item, index) in list" :key="index">
<!-- 非叶子节点 -->
<el-submenu v-if="item.children" :index="item.path">
<template slot="title">
<i class="el-icon-location"></i>
<span class="menu" slot="title">{{ item.name }}</span>
</template>
<left-menu :dataToSon="item.children"></left-menu>
</el-submenu>
<!-- 叶子节点(功能节点) -->
<el-menu-item v-else :index="item.path">
<i class="el-icon-menu"></i>
<span class="menu" slot="title">{{ item.name }}</span>
</el-menu-item>
</fragment>
</div>
</template>
<script>
import leftMenu from '../../../src/views/home/leftMenu.vue'
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'leftMenu',
components: {
leftMenu
},
props: ['dataToSon'],
data () {
return {
isCollapse: false,
list: []
}
},
mounted () {
this.list = this.dataToSon
},
methods: {
handleOpen (key, keyPath) {
console.log(key, keyPath)
},
handleClose (key, keyPath) {
console.log(key, keyPath)
}
}
}
</script>
<style scoped>
</style>
multipleTabs.vue代码
<template>
<div>
<el-tabs v-model="activeTab" type="card" closable @tab-remove="rem">
<el-tab-pane
v-for="item in this.$store.state.tabOne"
:key="item.id"
:label="item.name"
:name="item.path"
>
<router-view :name="item.path" v-slot="{Component}">
<keep-alive>
<component :is="Component"></component>
</keep-alive>
</router-view>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
export default {
name: 'MultipleTabs',
computed: {
...mapState({
vuexActiveTab: 'title'
}),
activeTab: {
get () {
return this.vuexActiveTab
},
set (newValue) {
this.handleTabChange(newValue)
}
}
},
data () {
return {
editableTabsValue: this.$store.state.title
}
},
mounted () {
console.log(this.$store.state.title)
},
methods: {
...mapMutations(['SET_ACTIVE_TAB']),
handleTabChange (tab) {
this.SET_ACTIVE_TAB(tab)
},
rem (e) {
this.$store.commit('remove', e)
}
}
}
</script>
<style scoped>
</style>
在写vuex代码前先安装一个vuex数据状态持久化-vuex-persistedstate插件来实现刷新页面数据还存在
我这里是直接用的总仓库来写的
vuex里的代码store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
tree: [
{
path: 'vv',
name: '首页',
func_fid: 0,
id: '1000',
children: [
{
path: 'sy',
name: '首页儿子',
func_fid: 1000,
id: '1212'
}
]
},
{
path: 'hh',
name: '系统管理',
func_fid: 0,
id: '1',
children: [
{
id: '1-1',
func_fid: 1,
path: 'son1',
name: '系统管理儿子'
},
{
id: '2',
func_fid: 1,
path: 'hhh',
name: '系统管理-角色',
children: [
{
id: '222',
func_fid: 1,
path: 'son1-1-1',
name: '角色管理',
children: [
{
id: '12',
func_fid: 2,
path: 'son1-1-1',
name: '角色管理儿子',
children: [
{
id: '122',
func_fid: 2,
path: 'son1-1-1-1',
name: '角色管理儿子-----孙子'
}
]
}
]
}
]
},
{
id: '122',
path: 'son1-2',
name: '用户管理'
}
]
},
{
path: 'ss',
name: '教学管理',
id: '22',
func_fid: 0,
children: [
{
path: 'son2',
name: '教学管理儿子',
id: '202',
func_fid: 22
}
]
},
{
path: 'zz',
name: '行政管理',
id: '3',
func_fid: 0,
children: [
{
path: 'son3',
name: '行政管理儿子',
id: '33',
func_fid: 3
}
]
},
{
path: 'cv',
name: '测试管理',
id: '4',
func_fid: 0,
children: []
}
],
tabs: [],
tabOne: [],
title: ''
},
getters: {
},
mutations: {
tab (state, payload) {
function recursion (t) {
state.tabs.push(t)
if (t.children && t.children.length > 0) {
for (let i = 0; i < t.children.length; i++) {
recursion(t.children[i])
}
}
}
state.tree.forEach(item => {
recursion(item)
})
state.tabs.forEach(item => {
if (item.path === payload) {
const ind = state.tabOne.findIndex(i => i.path === item.path)
state.title = item.path
if (ind === -1) {
state.tabOne.push(item)
}
}
})
},
SET_ACTIVE_TAB (state, newValue) {
state.title = newValue
},
remove (state, payload) {
console.log(payload)
const i = state.tabOne.findIndex(item => item.path === payload)
if (payload !== state.title) {
console.log(payload)
} else if (state.tabOne.length === 1) {
state.title = ''
} else if (i === state.tabOne.length - 1) {
state.title = state.tabOne[i - 1].path
} else {
state.title = state.tabOne[i + 1].path
}
state.tabOne.splice(i, 1)
}
},
actions: {
},
modules: {
},
plugins: [createPersistedState({
storage: window.sessionStorage
})]
})
这个是我的git仓库地址有需要的可以自行拉取
路由代码
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: () => import('../views/home/home.vue'),
children: [
{
path: '',
components: {
son1: () => import('../views/home/son/sonOne.vue'),
son2: () => import('../views/home/son/sonTwo.vue'),
son3: () => import('../views/home/son/sonThree.vue')
}
}
]
}
]
const router = new VueRouter({
mode: 'hash',
base: process.env.BASE_URL,
routes
})
export default router