记录Vue动态添加菜单路由
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动态添加路由就完成了,如有错误,欢迎指正!
更多推荐
已为社区贡献1条内容
所有评论(0)