vue动态添加路由之避坑指南:https://www.it610.com/article/1517505460574420992.htm

 

你是否遇到了:

  • addRouter后出现白屏
  • 路由守卫出现死循环

踩了很多坑之后,我终于悟到了vue动态添加路由的正确打开方式;

为了设计权限,在前端我们通常采取两种方式
1、在用户登录时获取该用户权限下的路由表,动态生成路由和菜单栏(后端给定路由)
2、在用户登录时获取用户权限,根据权限筛选出需要的路由(前端通过权限筛选路由)

本篇文章采用方式一

关键点:

  • 使用route中addRouter方法动态添加路由
  • 将路由分为
    (1)动态路由 myRouterObj (可从后端获取)
    (2) 静态路由 staticRoutes 没有权限也可以访问的路由
    注:rootRouter 用来组装动态路由。

router index.js页面

import Vue from 'vue'
import Router from 'vue-router' import home from '@/pages/Home' import store from '../store/store' Vue.use(Router) // 动态路由 模拟后端数据 const myRouterObj = [ { path: '/dashboard', name: "dashboard", meta: { title: '系统首页' }, component: "Dashboard" }, { path: '/table', name: "commonTable", meta: { title: '表格' }, component: "CommonTable" }, { path: '/calendar', name: "calendar", meta: { title: '日历' }, component: "Calendar" } ] // 静态路由 没有权限也可以访问的路由 export const staticRoutes = [ { path: "/login", name: "login", component: () => import( "@/pages/Login.vue" ), } ]; // 根路由 const rootRouter = { path: '/', name: 'home', component: home, redirect: '/dashboard', children: [] }; export const generatorDynamicRouter = () => { return new Promise((resolve, reject) => { // myRouterObj 这里直接写在页面中了,实际应用中我们需要进行ajax请求获取 const routesForHis = generatorForHis(myRouterObj); // routesForHis .push(notFoundRouter); // 可以定义404nofoun单页面路由 rootRouter.children = routesForHis; resolve(rootRouter); }); }; export const generatorForHis = (routeMap) => { return routeMap .map(item => { const currentRouter = { path: item.path, // 路由名称,建议唯一 name: item.name, // meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉) meta: item.meta, // 该路由对应页面的 组件 (动态加载 @/pages/ 下面的路径文件) component: () => import(`@/pages/` + item.component + '.vue') }; // 子菜单,递归处理 if (item.children && item.children.length > 0) { currentRouter.children = generatorForHis(item.con); if (currentRouter.children === undefined || currentRouter.children.length <= 0) { delete currentRouter.children; } } return currentRouter; }) .filter(item => item); }; // 开始创建路由时 const router = new Router({ mode: 'history', base: '/', linkActiveClass: "active", routes: staticRoutes }) router.beforeEach(async (to, from, next) => { var isLogin = store.state.isLogin; if (to.path == "/login") { next() } else { if (isLogin) { if (store.state.allowRouters && store.state.allowRouters.length > 0) { // 路由的出口 判断addRoute是否已经完成 避免路由守卫进入死循环 next() } else { const allowRouters = await store.dispatch("GENERATE_ROUTES_DYNAMIC", "aa") if (allowRouters.children.length == 0) { return false; } if (allowRouters) { next({ ...to, replace: true }) } return false; } } else { next('/login') } } }) export default router; 

store store.js文件

import Vue from 'vue'
import Vuex from 'vuex' import { generatorDynamicRouter } from '@/router' import { default as router, staticRoutes } from '@/router'; Vue.use(Vuex) let isLogin = '' try { if (localStorage.isLogin) { isLogin = JSON.parse(localStorage.isLogin) } } catch (e) { } export default new Vuex.Store({ state: { isLogin: isLogin, allowRouters: [], }, mutations: { login(state) { state.isLogin = true; localStorage.isLogin = true; }, SET_ROUTERS(state, data) { state.allowRouters = data; }, }, actions: { // 产生动态路由 GENERATE_ROUTES_DYNAMIC({ commit }, data) { return new Promise(resolve => { generatorDynamicRouter() .then((routes) => { const allowRoutes = routes.children || []; // 添加到路由表 console.log('allowRoutes: ', allowRoutes); router.addRoute(routes); commit('SET_ROUTERS', allowRoutes); resolve(routes); }) .catch(err => { console.error('generatorDynamicRouter', err); }); }); }, } }) 

关于next({ ...to, replace: true })的理解
很多人在使用动态添加路由addRoutes()会遇到下面的情况:

  • 问题:在addRoutes()之后,第一次访问被添加的路由会白屏。
  • 原因:在addRoutes()之后,立刻访问被添加的路由时,addRoutes()没有执行结束,因而找不到刚刚被添加的路由导致白屏。
  • 解决方案:需要重新访问一次路由才行。

该如何解决这个问题 ?
此时就要使用next({ ...to, replace: true })来确保addRoutes()时动态添加的路由已经被完全加载上去。

关于next({ …to, replace: true })

  1. replace: true只是一个设置信息,告诉VUE本次操作后,不能通过浏览器后退按钮,返回前一个路由。
  2. next({ ...to })的执行很简单,它会判断:
    如果参数to不能找到对应的路由的话,就再执行一次路由守卫(beforeEach((to, from, next))直到其中的next({ ...to})能找到对应的路由为止。

next({ ...to, replace: true })可以保证addRoutes()已经执行完成,路由中已经有我们后来添加进去的用来路由了。
找到对应的路由之后,接下来将前往对应路由,并执行路由守卫(beforeEach((to, from, next)),因此需要用代码来判断是否可以该入改路由(本文的代码根据store中的allowRoutes的长度是否大于零来确定是否进行next()),如果是,就执行next()放行。

如果守卫中没有正确的放行出口的话,会一直next({ ...to})进入死循环 !!!

因此你还需要确保在当addRoutes()已经完成时,所执行到的这一次路由守卫beforeEach((to, from, next)中有一个正确的next()方向出口。

以下就是上述内容的伪代码,敲重点

if (store.state.allowRouters && store.state.allowRouters.length > 0) { // 路由的出口 addRoute已经完成 避免路由守卫进入死循环 next() } else{ router.addRoute('要添加的路由'); // 保证addRoute已经完成,并导航到对应的路由 next({ ...to, replace: true }) }

原文地址:http://www.cnblogs.com/bydzhangxiaowei/p/16811566.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性