实现功能:点击mean的子菜单,tabs显示子菜单名称。并且可以进行删除,刷新之后,停留在刷新前的界面。
使用到的组件el-menu ,el-tabs。
使用到的工具:vue-router,vuex
实现效果:
项目目录:
App.vue
<template> <div id="app"> <el-container> <el-aside width="300px"> <Home></Home> <!-- 我是侧边栏 --> </el-aside> <el-container> <el-main> <tabs></tabs> <!-- 我是tabs组件 --> </el-main> </el-container> </el-container> </div> </template> <script> import Home from '../src/views/Home' import tabs from '../src/views/tabs' export default { components:{ Home, tabs } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; /* text-align: center; */ color: #2c3e50; } #nav { padding: 30px; } #nav a { font-weight: bold; color: #2c3e50; } #nav a.router-link-exact-active { color: #42b983; } </style>
tabs.vue
<template> <div class> <el-tabs v-model="editableTabsValue" type="card" closable @tab-remove="removeTab" @tab-click="tabClick($event)" > <el-tab-pane :key="item.name" v-for="item in editableTabs" :label="item.title" :name="item.name" ></el-tab-pane> </el-tabs> <router-view /> </div> </template> <script> export default { name: "", components: {}, data() { return {}; }, mounted() { //刷新加载sessionStorage存着地址 if (sessionStorage.getItem("tabsPage")) { this.$store.state.tabsPage = JSON.parse( sessionStorage.getItem("tabsPage") ); var TabsValue = sessionStorage.getItem("TabsValue"); this.$store.state.TabsValue = TabsValue; if (sessionStorage.getItem("tabsPage") === "[]") { this.$router.push({ name: "Home" }); } else { this.$router.push({ name: TabsValue }); } } }, computed: { // 监听vuex保存的数据 editableTabs: { get() { return this.$store.state.tabsPage; }, set(val) { this.$store.state.tabsPage = val; }, }, editableTabsValue: { get() { return this.$store.state.TabsValue; }, set(val) { this.$store.state.TabsValue = val; }, }, }, methods: { removeTab(targetName) { let tabs = this.editableTabs; let activeName = this.editableTabsValue; if (activeName === targetName) { tabs.forEach((tab, index) => { if (tab.name === targetName) { let nextTab = tabs[index + 1] || tabs[index - 1]; console.log(nextTab); if (nextTab) { activeName = nextTab.name; } } }); } this.editableTabsValue = activeName; this.editableTabs = tabs.filter((tab) => tab.name !== targetName); this.$store.state.tabsPage = this.editableTabs; window.sessionStorage.tabsPage = JSON.stringify(this.editableTabs); //解决刷新消失 window.sessionStorage.setItem("TabsValue", activeName); // 删除时跳转不在停留被删除页 if (sessionStorage.getItem("tabsPage") === "[]") { this.$router.push({ name: "home" }); } else { this.$router.push({ name: activeName }); } }, tabClick(event) { //写一个点击tabs跳转 this.$router.push({ name: event.name }); }, }, }; </script>
Home.vue
<style lang="less" scoped> .el-menu-vertical-demo:not(.el-menu--collapse) { min-height: 97.3vh; width: 14rem; } .el-menu { padding-top: 2.7vh; } .el-submenu__title i, .el-menu-item i { color: #909399; position: relative; right: 0.4rem; font-size: 12px; } .el-menu-item { min-width: auto !important; } .el-submenu /deep/ .el-submenu__title .el-submenu__icon-arrow { position: absolute; right: 2rem; } </style> <template> <div class="height:100%"> <!-- :default-active="$route.name" 获取router路由的name 对应menu-item内的index 为了对应 tabs 的跳转点击 做选中 --> <el-menu :default-active="$route.name" class="el-menu-vertical-demo" background-color="#545c64" text-color="white" active-text-color="#ffd04b" > <!-- 循环数据格式 --> <el-submenu :index="`${index}`" v-for="(menu,index) in menuList" :key="index"> <template slot="title"> <i :class="menu.icont"></i> <span>{{menu.name}}</span> </template> <el-menu-item-group> <el-menu-item :index="item.routeName" v-for="item in menu.menuItem" :key="item.index" @click="handleOpen2(item)" >{{item.name}}</el-menu-item> </el-menu-item-group> </el-submenu> </el-menu> </div> </template> <script> import { mapActions } from "vuex"; export default { name: "zgz-admin-index-aside", components: {}, data() { return { // 将所需submenu,menu和tabs所需参数写成数据格式 menuList: [ { icont: "el-icon-s-tools", name: "子菜单", menuItem: [ { title: "子菜单1", routeName: "Setting", name: "子菜单1", }, { title: "子菜单2", routeName: "WxAd", name: "子菜单2", }, ], }, { icont: "el-icon-s-tools", name: "子菜单呀", menuItem: [ { title: "子菜单呀1", routeName: "Setting", name: "子菜单呀1", }, { title: "子菜单呀2", routeName: "WxAd", name: "子菜单呀2", }, ], }, { icont: "el-icon-s-order", name: "子菜单啊呀", menuItem: [ { title: "子菜单啊呀1", routeName: "orderList", name: "子菜单啊呀1", }, { title: "子菜单啊呀2", routeName: "orderList", name: "子菜单啊呀2", }, ], }, ], }; }, created() {}, mounted() {}, methods: { // 调用 注册vuex内注册的editableTabs方法 ...mapActions({ handleOpen2: "editableTabs", }), }, }; </script>
store中的index.js
import Vue from 'vue'; import Vuex from 'vuex'; // 引入 router 在vuex内使用router跳转 import router from '../router'; Vue.use(Vuex); Vue.use(router); export default new Vuex.Store({ state: { // 定义tabs 所需参数 tabsPage: [], TabsValue: '' }, mutations: { editableTabs: (state, obj) => { // 浅拷贝 state.tabsPage const arr = Array.from(state.tabsPage) // 判断数组内是否为空 if (arr.length !== 0) { // 使用 Array.some 去判断是否存在对象信息 var even = function (obj) { return arr.some(item => { return item.name === obj.routeName }) } // even方法 如果对象存在返回true,不存在则返回flase // 加!触发 true 代码块 if (!even(obj)/* 如果不存在将对象push进数组内bing */) { // 将tabs所需参数push进arr数组 arr.push({ title: obj.name, name: obj.routeName }) // 赋值给tabsPage参数 state.tabsPage = arr // 存储sessionStorage -- 解决刷新消失 window.sessionStorage.setItem('tabsPage', JSON.stringify(arr)) window.sessionStorage.setItem('TabsValue', obj.routeName) // 赋值给TabsValue参数 state.TabsValue = obj.routeName // 跳转 router.push({ name: obj.routeName }) } else { // 如果存在 只做跳转选中 // 赋值给TabsValue参数 state.TabsValue = obj.routeName window.sessionStorage.setItem('TabsValue', obj.routeName) // 跳转 router.push({ name: obj.routeName }) } } else { // 如果为0 // 将tabs所需参数push进arr数组 arr.push({ title: obj.name, name: obj.routeName }) // 赋值给tabsPage参数 state.tabsPage = arr // 赋值给TabsValue参数 state.TabsValue = obj.routeName // 跳转 router.push({ name: obj.routeName }) } } }, actions: { // 注册方法 editableTabs(context, obj) { context.commit('editableTabs', obj) } } })
router中的index.js
import Vue from 'vue' import VueRouter from 'vue-router' import Setting from '../views/Setting.vue' import WxAd from '../views/WxAd.vue' import orderList from '../views/orderList.vue' Vue.use(VueRouter) const originalPush = VueRouter.prototype.push VueRouter.prototype.push = function (location, onResolve, onReject) { if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject) return originalPush.call(this, location).catch(err => err) } const routes = [ { path: '/home', name: 'Home', }, { path: '/Setting', name: 'Setting', component: Setting }, { path: '/WxAd', name: 'WxAd', component: WxAd }, { path: '/orderList', name: 'orderList', component: orderList } ] const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }) export default router