效果图:
话不多说上代码
一、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