记录Vue动态添加菜单路由

前言:

管理系统默认只存在登录页面这一个路由。

import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
  {
    path: '/login',
    name: 'Login',
    component: () => import('@/views/Login.vue'),
    meta: {
      title: "登录",
      isSub: false,
    }
  },
]
const router = new VueRouter({
  routes
})
// 重新添加路由方法  避免添加已经存在路由警告
router.$addRoutes = (params) => {
  router.matcher = new VueRouter({
    mode: 'history'
  }).matcher
  router.addRoutes(params)
}
export default router

一、登录账号获取菜单树。

第一步,通过登录账号获取后端返回的菜单数据,假如格式如下:

二、封装一个方法处理菜单树数据。

        2.1拿到菜单树可能是不限层级的json树,因此我们需要封装一个方法去递归处理,将第一步拿到的组件路径转为路由可以识别的文件路径。 

// 引入布局组件
import Layout from "@/views/Layout.vue";
import SubLayout from '@/views/SubLayout.vue';
// 处理动态路由组件
export function _import(file) {
  return () => import('@/views/' + file + '.vue')
}
// 递归生成动态路由菜单集合
export function filterRouter(routers) {
  // 遍历后台传来的路由字符串,转换为组件对象
  const accessedRouters = routers.filter((route) => {
    if (route.name) {
      if (route.component === "Layout") {
        route.component = Layout;
      } else if (route.component === "SubLayout") {
        route.component = SubLayout;
      } else {
        route.component = _import(route.component);
      }
    }
    // 此处代码是根据项目路由设计需做一些特殊处理 可忽略
    if (route.children && route.children.length) {
      route.children = filterRouter(route.children);
    } else {
      if (route.redirect) {
        route.children = [{
          path: route.redirect,
          name: route.name,
          component: _import(route.name),
          meta: route.meta
        }]
        route.name = "";
      }
    }
    return true;
  });
  return accessedRouters;
}

        2.2 方法封装好之后,就可以在登录成功之后,将拿到的数据转换成我们需要的路由数据。

//获取到后端返回的菜单数据
let { menus } = res.result.menus;  
// 处理菜单数据
let newMenus = filterRouter(menus); 
// 将处理后的菜单数据添加到路由
this.$router.$addRoutes(newMenus);  

// tips:vue-router 3.0有addRoutes()方法,4.0被废弃了
// 可以使用addRoute()遍历添加
// newMenus.map((item, index) => {
//   this.$router.addRoute(item);
// });

到这里动态添加路由就算完成了。这就引出一个新的问题,除了登录页面是默认就存在的,其他路由都是动态添加,所以如果页面刷新,页面会空白,这是因为页面刷新路由数据丢失造成的。要解决这个问题,就需要来到路由守卫,在路由守卫里检测动态添加的路由是否存在,不存在的话需要再次添加进去。这样就解决了页面刷新路由丢失的问题。

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import {filterRouter} from "@/utils/handleRoute";
// 路由拦截
router.beforeEach((to, from, next) => {
  if (to.meta.title) {
    document.title = to.meta.title
  }
  let token = window.sessionStorage.getItem('token');
  // 是否有token  没有token 进登录
  if (token) {
    // 有token 访问登录页 直接去首页 免登录
    if (to.path == '/login') {
      next({
        path: '/index'
      });
    } else {
      // 判断当前是否已经生成完整的路由 如果已经生成直接next(),不然会栈溢出
      let allRoutes = router.getRoutes();
      if (allRoutes.length > 6) {    // 大于6 是因为项目除了默认包含登录路由 还默认内置了其他路由
        if (to.matched.length === 0 && to.path !='/404') {
          next({path:'/404',replace:true}) // 判断此跳转路由的来源路由是否存在,存在的情况跳转到来源路由,否则跳转到404页面
        } else {
          next();
        }
      } else {
        // 有token 访问非登录页 去获取缓存的菜单数据 生成菜单 
        let menuData = JSON.parse(window.sessionStorage.getItem("menu"));
        console.log(menuData);
        if (menuData && menuData.menus.length>0) {
          let {
            menus
          } = JSON.parse(window.sessionStorage.getItem("menu"));
          let menusRoute = filterRouter(menus);
          router.addRoutes(menusRoute);
            next({
              path: to.path,
              replace: true,
            })
        }
      }
    }
  } else {
    // 判断当前是否已经在登录页 避免已经在登陆页还一直进入登录页 导致栈溢出
    if (to.path != "/login") {
      next({
        path: '/login'
      })
    } else {
      next();
    }
    window.sessionStorage.setItem('token', '');
    window.sessionStorage.setItem("menu", "");
    window.sessionStorage.setItem("userInfo", "");
  }
})

这里需要注意的是, 处理好next()的调用时机,不然会出现栈溢出。

总结:

        vue动态添加路由就完成了,如有错误,欢迎指正!

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值