The process is that the user enters the module page after logging in, clicks on different modules, and enters the menu page (different modules, different menu contents)
Problems encountered
1. The menu data is stored in the store and the page is blank after refreshing
Solution: initialize the menu every time in the global navigation guard
2. How to generate routes dynamically (dynamically generated routes will be overlapped, and a warning will be given if they already exist)
created() { this.routePath = this.$route.path; },
All of the following use json simulation data
The detailed code is as follows
userPermission.json
{ "data":{"name":"petty thief"}, "token":"111", "responseCode":"0000" }
Login.vue
<template> <div> <el-form :rules="rules" ref="loginForm" v-loading="loading" element-loading-text="Logging in..." element-loading-spinner="el-icon-loading" element-loading-background="rgba(0, 0, 0, 0.8)" :model="loginForm" class="loginContainer" > <h3 class="loginTitle">System login</h3> <el-form-item prop="username"> <el-input size="normal" type="text" v-model="loginForm.username" auto-complete="off" placeholder="enter one user name" ></el-input> </el-form-item> <el-form-item prop="password"> <el-input size="normal" type="password" v-model="loginForm.password" auto-complete="off" placeholder="Please input a password" @keydown.enter.native="submitLogin" ></el-input> </el-form-item> <el-checkbox size="normal" class="loginRemember" v-model="checked"></el-checkbox> <el-button size="normal" type="primary" style="width: 100%;" @click="submitLogin">Sign in</el-button> </el-form> <div class="login-bottom"> bottom </div> </div> </template> <script> export default { name: "Login", data() { return { loading: false, loginForm: { username: "admin", password: "1" }, checked: true, rules: { username: [ { required: true, message: "enter one user name", trigger: "blur" } ], password: [{ required: true, message: "Please input a password", trigger: "blur" }] } }; }, methods: { submitLogin() { this.$refs.loginForm.validate(valid => { if (valid) { this.loading = true; this.$axios .get("mock/userPermission.json") .then(res => { console.log(res.data); let data = res.data if(data.responseCode=="0000"){ this.$store.commit("updatePermissionInfo", res.data); sessionStorage.setItem("user", data.data.name); sessionStorage.setItem("token", data.token); this.$router.push("/dashboard"); } }) .catch(error => { console.log(error.response) this.$alert(error, "Tips", { confirmButtonText: "Determine", type: "warning" }); }); } else { this.$message.error("Please enter all fields"); return false; } }); } } }; </script> <style scoped> .loginContainer { width: 450px; height: 320px; border-radius: 15px; background: #fff; position: absolute; left: 0; right: 0; top: -60px; bottom: 0; /* background:linear-gradient(to bottom,#0675bd, #0363a1); */ box-shadow: 0 0 25px #cac6c6; padding: 15px 35px 15px 35px; margin: auto; } .loginTitle { margin: 15px auto 20px auto; text-align: center; color: #505458; } .loginRemember { text-align: left; margin: 0px 0px 15px 0px; } .loginTip { color: #d31245; font-style: italic; margin-bottom: 25px; } .login-bottom { position: fixed; bottom: 15px; width: 100%; text-align: center; } .login-bottom img { vertical-align: middle; width: 65px; margin-right: 10px; } </style>
Module page
dishboardInfo.json
{ "data": [{ "id":1, "path": "/industry", "name": "Module 1", "component": "Home" }, { "id":2, "path": "/commercial", "name": "Module 2", "component": "Home" }] }
dashboard.vue
<template> <div class> <ul class="dashboard"> <!-- <router-link tag="li" v-for="(item,index) in info" :key="index" :to="item.path">{{item.menuName}}</router-link> --> <li v-for="(item,index) in info" :key="index" @click="handleClick(index)">{{item.name}}</li> </ul> </div> </template> <script> export default { data() { return { info: [] }; }, created() { let userName = sessionStorage.getItem("user"); console.log(userName); this.$axios.get("mock/dishboardInfo.json").then(res => { console.log(res.data); this.info = res.data.data; }); }, computed: {}, methods: { handleClick(index) { this.$router.push({ path: this.info[index].path, query: { menuId: this.info[index].id } }); } } }; </script>
Route
import Vue from 'vue' import VueRouter from 'vue-router' import Login from '../views/Login.vue' import Dashboard from '../views/dashboard.vue' import Home from '../views/Home.vue' Vue.use(VueRouter) // const originalPush = VueRouter.prototype.push // VueRouter.prototype.push = function push(location) { // return originalPush.call(this, location).catch(err => err) // } const routes = [{ path: '/', redirect: "/login", }, { path: "/login", name: 'login', component: Login }, { path: "/dashboard", name: 'dashboard', component: Dashboard }, { path: '/:id', name: "home", //component: () => import('../views/Home.vue') component: Home, } ] const router = new VueRouter({ routes }) export default router
Store
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { currentModule: sessionStorage.getItem("currentModule") || "", currentMenuId: sessionStorage.getItem("currentMenuId") || "", //routes:[], routes: { industry: [], commercial: [], person: [] }, permissionInfo: JSON.parse(sessionStorage.getItem("permissionInfo")) || {}, }, mutations: { updatePermissionInfo(state, permissionInfo) { state.permissionInfo = permissionInfo }, initRoutes(state, data) { console.log(data) if (data) { state.routes[data.key] = data.value } else { state.routes = { industry: [], commercial: [] } } // if (JSON.stringify(data) == "{}"){ // console.log("empty object") // state.routes = { // industry: [], // commercial: [] // } // return // } // console.log("with objects") // state.routes[data.key]= data.value }, setCurrentModule(state, currentModule) { state.currentModule = currentModule sessionStorage.setItem("currentModule", currentModule) }, setCurrentMenuId(state, currentMenuId) { state.currentMenuId = currentMenuId sessionStorage.setItem("currentMenuId", currentMenuId) } }, actions: {}, modules: {} })
menu.js
import axios from 'axios' export const initMenu = (router, store, to) => { if (to.path == "/dashboard" || to.path == "/login") { return } let currentMenuId = to.query.menuId || sessionStorage.getItem("currentMenuId") let currentModule = to.params.id || sessionStorage.getItem("currentModule") console.log(currentModule) if (currentModule && store.state.routes[currentModule].length > 0) { //sessionStorage.setItem("currentModule", currentModule) store.commit("setCurrentModule", currentModule) store.commit("setCurrentMenuId", currentMenuId) console.log("return") return; } else { //console.log("nei-1") axios.get("mock/menudata-"+currentModule+".json").then(res => { let data = res.data.data let fmRoutes = formatRoutes(data); //router.options.routes = fmRoutes router.addRoutes(fmRoutes); let dataObj = {} dataObj.key = currentModule dataObj.value = data console.log(dataObj) //dataObj.value = fmRoutes store.commit("initRoutes", dataObj) store.commit("setCurrentModule", currentModule) store.commit("setCurrentMenuId", currentMenuId) }); } } export const formatRoutes = (menuData) => { //console.log(data); let fmRoutes = []; menuData.forEach(item => { let { path, menuName, component, childMenu } = item; //console.log(children) if (childMenu && childMenu instanceof Array) { childMenu = formatRoutes(childMenu); } let fmRouter = { path: path, name: menuName, children: childMenu, component(resolve) { if (component.startsWith("Home")) { require(["../views/" + component + ".vue"], resolve); } else if (component.startsWith("Baobiao")) { require(["../views/baobiao/" + component + ".vue"], resolve); } else if (component.startsWith("DataAccount")) { require(["../views/dataAccount/" + component + ".vue"], resolve); } } //component: () => import("../views/" + component + ".vue") }; fmRoutes.push(fmRouter); }); //console.log(fmRoutes); return fmRoutes; }
main.js
import Vue from 'vue' import App from './App.vue' import router from './router' import store from './store' // Introducing element UI components import ElementUI from 'element-ui' // Import element UI style file import 'element-ui/lib/theme-chalk/index.css' import './assets/js/jQuery-2.1.4.min.js' import axios from "axios" import '@/assets/css/global.css' import 'font-awesome/css/font-awesome.min.css' import {hasPermission} from "./utils/hasPermission" import {initMenu} from "./utils/menu" Vue.use(ElementUI) //axios.defaults.baseURL = 'http://xxxxx' // var instance = axios.create({ // baseURL: 'http://localhost:8080/' // }); // Vue.prototype.$instance = instance //Add a request interceptor // axios.interceptors.request.use(function (config) { // config.data=JSON.stringify(config.data); // return config; // }, function (error) { // // Do something with request error // console.info("error: "); // console.info(error); // return Promise.reject(error); // }); import qs from "qs"; Vue.prototype.$qs = qs; Vue.prototype.$axios = axios Vue.prototype.hasPerm = hasPermission Vue.config.productionTip = false //Normal code router.beforeEach((to, from, next) => { let token = window.sessionStorage.getItem('token'); if (to.path != '/login' && !token) { next({ path: '/login' }) } else { if (to.path == '/login' && token) { next('/dashboard') } else { initMenu(router,store,to) next() } } }) var VUE = new Vue({ router, store, render: h => h(App) }).$mount('#app')
Home.vue
<template> <div> <el-container :style="{height: containerHeight, border: '1px solid #eee'}" id="con"> <el-header style="background:#3c8dbc;"> <div class="left pull-left"> <img src="../assets/imgs/weeglogo.png" alt /> <span>Current module:</span> <span>{{currentModuleToChinese}}</span> </div> <div class="right pull-right"> <router-link to="/dashboard"> <i class="fa fa-home margin_r20" style="font-size:20px;" aria-hidden="true"></i> </router-link> <span class="margin_r20">{{user}}</span> <span style="color:#f9c05e;" @click="logout"> <i class="fa fa-power-off" aria-hidden="true"></i> //Cancellation </span> </div> </el-header> <el-container> <el-aside width="230px"> <el-menu router :default-active="routePath" unique-opened background-color="#1f3146" text-color="#32acca" active-text-color="#ffd04b" > <NavMenu :navMenus="menuData"></NavMenu> </el-menu> </el-aside> <el-container> <el-main> <el-tabs :value="activeTabItem" @tab-remove="closeTab" class="content-body" @tab-click="tabClick" > <el-tab-pane label="home page" name="adminIndex"> <admin-index></admin-index> </el-tab-pane> <el-tab-pane v-for="item in tabs" :label="item.label" :key="item.index" :name="item.index+''" :closable="item.closable" > </el-tab-pane> </el-tabs> <bread-crumb></bread-crumb> <!-- <div>{{breab}}</div> --> <router-view></router-view> </el-main> <el-footer> footer </el-footer> </el-container> </el-container> </el-container> </div> </template> <script> import NavMenu from "@/components/NavMenu.vue"; import BreadCrumb from "@/components/Breadcrumb.vue"; import AdminIndex from "@/components/AdminIndex.vue"; export default { data() { return { containerHeight: "", //menuData: [], routePath: "", currentModuleChinese: "", user: window.sessionStorage.getItem("user") }; }, created() { this.routePath = this.$route.path; }, computed: { menuData() { let id = this.$store.state.currentModule; console.log(id); console.log(this.$store.state.routes[id]); return this.$store.state.routes[id]; }, currentModuleToChinese() { let currentModule = this.$store.state.currentModule; switch (currentModule) { case "industry": return "Module 1"; break; case "commercial": return "Module 2"; break; case "person": return "Module 3"; break; } }, tabs(){ return this.$store.state.tabs }, activeTabItem(){ return this.$store.state.activeTabItem } }, components: { NavMenu, BreadCrumb }, methods: { logout() { this.$confirm("This operation will log out. Do you want to continue?", "Tips", { confirmButtonText: "Determine", cancelButtonText: "cancel", type: "warning" }) .then(() => { //this.$axios.get("/logout"); window.sessionStorage.removeItem("token"); window.sessionStorage.removeItem("currentMenuId"); //this.$store.commit("initRoutes",{}) //this.$store.commit("initRoutes",null) console.log(this.$store.state.routes); location.reload(); //this.$router.replace("/") }) .catch(() => { this.$message({ type: "info", message: "Operation cancelled" }); }); } }, // watch:{ // $route(){ // console.log(this.$route.path) // this.routePath = this.$route.path // } // }, mounted() { console.log("mounted"); this.containerHeight = window.innerHeight + "px"; console.log($); $(window).resize(function() { console.log("hi"); $("#con").height($(window).height() - 2); }); //this.$router.push("/industrySub2") } }; </script> <style> .el-header { background-color: #377fa9; color: #fff; height: 50px !important; line-height: 50px !important; } .el-header .left img { width: 120px; vertical-align: middle; } .el-header .left span { font-size: 20px; color: #edf8ff; margin-left: 15px; } .el-header .right { float: right; } .el-header .right a { color: #fff; } .el-aside { /* color: #32acca !important; */ background: #1f3146 !important; } .el-menu { border-right: none !important; /* background: #1f3146 !important; */ } .el-main{padding-top:0 !important;} .el-footer { background: gray; height: 40px !important; line-height: 40px !important; } .el-footer { border-top: 1px solid #ccc; background: #f8fafd; padding: 10px; margin-left: 0; } .el-footer img { vertical-align: middle; width: 65px; margin-right: 10px; } </style>
There is a detailed introduction to limitless menu in the last blog