前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >动态加载用户菜单

动态加载用户菜单

作者头像
tianyawhl
发布2020-02-18 13:31:05
2.2K0
发布2020-02-18 13:31:05
举报
文章被收录于专栏:前端之攻略

流程是用户登录后进入模块页面,点击不同的模块,进入菜单页面(模块不同,菜单内容也不同)

遇到的问题

1、菜单数据存储到store中页面刷新后页面空白

解决方法:在全局导航守卫中每次都初始化菜单

2、如何动态生成路由 (动态生成路由会叠加,如果已经存在再生成会警告)

采用方法:router . addRoutes ( data );

3、不同模块切换进入菜单页面,高亮显示有问题

解决方法:

: default-active = " routePath "

代码语言:javascript
复制
  created() {
    this.routePath = this.$route.path;
  },

3、退出登录后如何清空store中数据(vuex中并没有清空的方法)

暂时采用: location . reload ();

下面全部采用json模拟数据

详细代码如下

userPermission.json

代码语言:javascript
复制
{
"data":{"name":"小李"},
"token":"111",
"responseCode":"0000"
}

Login.vue

代码语言:javascript
复制
<template>
  <div>
    <el-form
      :rules="rules"
      ref="loginForm"
      v-loading="loading"
      element-loading-text="正在登录..."
      element-loading-spinner="el-icon-loading"
      element-loading-background="rgba(0, 0, 0, 0.8)"
      :model="loginForm"
      class="loginContainer"
    >
      <h3 class="loginTitle">系统登录</h3>
      <el-form-item prop="username">
        <el-input
          size="normal"
          type="text"
          v-model="loginForm.username"
          auto-complete="off"
          placeholder="请输入用户名"
        ></el-input>
      </el-form-item>
      <el-form-item prop="password">
        <el-input
          size="normal"
          type="password"
          v-model="loginForm.password"
          auto-complete="off"
          placeholder="请输入密码"
          @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">登录</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: "请输入用户名", trigger: "blur" }
        ],
        password: [{ required: true, message: "请输入密码", 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, "提示", {
                confirmButtonText: "确定",
                type: "warning"
              });
            });
        } else {
          this.$message.error("请输入所有字段");
          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>

模块页面

dishboardInfo.json

代码语言:javascript
复制
{
    "data": [{
        "id":1,
        "path": "/industry",
        "name": "模块1",
        "component": "Home"

    }, {
        "id":2,
        "path": "/commercial",
        "name": "模块2",
        "component": "Home"
    }]
}

dashboard.vue

代码语言:javascript
复制
<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>

路由

代码语言:javascript
复制
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

代码语言:javascript
复制
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("空对象")
      //   state.routes = {
      //     industry: [],
      //     commercial: []
      //   }
      //   return
      // }

      // console.log("有对象")
      // 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

代码语言:javascript
复制
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

代码语言:javascript
复制
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 引入element-ui 组件
import ElementUI from 'element-ui'
// 引入element-ui 样式文件
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
//添加一个请求拦截器
// 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

//正常运行的代码
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

代码语言:javascript
复制
<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>当前模块:</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>
            注销
          </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="首页" 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 "模块1";
          break;
        case "commercial":
          return "模块2";
          break;
        case "person":
          return "模块3";
          break;
      }
    },
    tabs(){
      return this.$store.state.tabs
    },
    activeTabItem(){
      return this.$store.state.activeTabItem
    }
  },
  components: { NavMenu, BreadCrumb },
  methods: {
    logout() {
      this.$confirm("此操作将注销登录,是否继续?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        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: "已取消操作"
          });
        });
    }
  },
  // 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>

关于无限极菜单,上一篇博客中有详细的介绍

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据保险箱
数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档