Dynamic load user menu

Keywords: Front-end Vue axios JSON JQuery

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)

Adopted method: router . addRoutes ( data );
 
3. Different modules switch to the menu page, highlighting the problem
resolvent:
: default-active = " routePath "
  created() {
    this.routePath = this.$route.path;
  },

 

3. How to clear the data in the store after logging out (there is no way to clear it in vuex)
Temporarily: location . reload ();
 

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

Posted by vandalite on Wed, 12 Feb 2020 07:16:43 -0800