vue-admin-template动态路由实现+问题解决

动态路由涉及的文件

  • mock
    • user.js
  • src
    • router
      • index.js
    • store
      • modules
        • permission.js
        • user.js
      • getters.js
      • index.js
  • permission.js

store\modules\permission.js在vue-admin-template中没有,可以直接复制粘贴vue-element-admin模板中的store\modules\permission.js

动态路由实现全过程

vue-admin-template模板只有最基础的功能,无法实现不同权限登录展示不同页面,上网搜索了很多文章,终于解决动态路由的实现以及过程中遇到的各种bug。

首先放上我参考最多的文章,一步步跟着博主走可以完成动态路由实现的基本代码:vue-element-template 根据权限动态加载路由

具体来说,动态路由的设置分为以下四个主要部分:
1.在router/index.js中分别写上通用页面路由constantRoutes和动态路由 asyncRoutes
2.存储一些相关用户信息
3. 筛选路由
4. 加载路由

遇到的bug

1. 无法获取用户信息的问题:“Login failed, unable to get user details.”

在这里插入图片描述
参考博客Property “visible” must be accessed with “$data.visible”

function hasPermission(roles, route) {
  if (route.meta && route.meta.roles) {
    if (route.meta.roles.indexOf(roles) > -1) {
      return true
    } else {
      return false
    }
    // return roles.some(role => route.meta.roles.includes(role))
  } else {
    return true
  }
}

曲线救国,通过查询错误【Property “visible” must be accessed with “$data.visible”】,把这个改了就可以获得用户信息了

2. 无法识别generateRoutes方法:“[vuex] unknown action type: permission/generateRoutes”

在这里插入图片描述
这个地方是参考的另一位博主的方法:Property “visible” must be accessed with “$data.visible”
store/index.js中添加两行即可解决
在这里插入图片描述

3. 遇到了跟原博主一样的问题:“data funtions should return an object”

在这里插入图片描述
这里是个大坑!
仔细比对过src\permission.js中的代码,逐句逐方法排查到了modules\permission.js文件中的generateRoutes方法中
在这里插入图片描述
发现运行到if语句时就无法进行下去了,既不进if,也不进else,打印roles发现:
在这里插入图片描述
roles是个Object,而includes()方法是判断数组中是否有某个元素,然后返回布尔值true/false,因此对rules使用includes()方法是无效的。对比原博主所写的博客,可以知道他在项目中只存入了rules权限,而没有存name、introduction、avatar等,因此博主使用

roles.includes(‘admin’)

判断用户是admin还是editor,但是我的项目不止存rules,还存了name、introduction、avatar,因此我应该使用

roles.roles.includes(‘admin’)

判断用户,完成这一步就可以登录进入主页了。

但是在module/permission.js中多次用到roles.roles对权限进行判断,因此,为了一劳永逸,应该在src/permission.js中将

const accessRoutes = await store.dispatch(‘permission/generateRoutes’, roles)

改为

const accessRoutes = await store.dispatch(‘permission/generateRoutes’, roles.roles)

4. 无法渲染左侧目录:permission_routes:undefined

我的左侧菜单不见了T T

在这里插入图片描述
仔细查对发现问题出在modules\permission.js中的

router.options.routes = store.getters.permission_routes

并且打印store发现permission_routes的值是undefined
在这里插入图片描述
考虑permission_routes的值应该为什么,从何处获取,再次查看getter.js,发现permission_routes从state中获取,但是实际上state中并没有permission_routes,发现问题了

在这里插入图片描述在这里插入图片描述

再次查看原博主的这一句是怎么写的,发现是自己抄错了

在这里插入图片描述

permission.routes抄成了permission_routes。但是这个地方很容易错,因为idea直接识别出来的就是permission_routes,一个不小心回车就酿成大错了。

在这里插入图片描述
到这个地方菜单已经能够完整显示出来了

5. 菜单渲染出错:accessRoutes值获取错误

我的需求和原博主相同,admin显示大菜单下的所有子菜单,editor显示大菜单下的两个子菜单

在这里插入图片描述
但是现在得到的结果是,admin显示大菜单下所有子菜单,但editor连大菜单都不显示了

在这里插入图片描述
在这里插入图片描述
打印存储着动态加载的权限路由的accessRoutes,发现问题

这是editor的accseeRoutes:

在这里插入图片描述

这是admin的accseeRoutes:

在这里插入图片描述
可以知道是动态路由的存储发生了问题。这个问题的关键在于modules\permission.js

用户在登陆后,开始进行权限验证,进入路由门卫src\permission.js中,当程序运行到

router.options.routes = store.getters.permission_routes

程序将跳转到modules\permission.js

modules\permission.js说白了就是干了一件事,通过用户的权限和之前在router.js里面asyncRouter的每一个页面所需要的权限做匹配,最后返回一个该用户能够访问路由有哪些

首先程序进*generateRoutes()函数,通过if-else语句区分用户admin和editor

如果用户为admin,则显示全部页面,并返回src\permission.js

如果用户为editor,则进入filterAsyncRoutes()函数,递归过滤异步路由表,返回符合用户角色权限的路由表

在这里插入图片描述
接下来,filterAsyncRoutes()函数通过hasPermission()验证开始筛选用户可访问的路由

在这里插入图片描述
此时程序又跳转到函数hasPermission()中,通过语句

route.meta.roles.indexOf(roles[0]) > -1

进行rolesroute.meta.roles的对比

例如,当roles = route.meta.roles = [“admin”]时,权限匹配,返回ture到filterAsyncRoutes()函数中,执行if语句,如果这个路由route含有子路由,则再次执行filterAsyncRoutes()函数递归验证。

在这里插入图片描述
最后,将筛选好的路由表存入res返回到generateRoutes()函数中,并存入accessedRoutes返回src\permission.js,动态筛选好的路由。

综上逻辑可知,在modules\permission.js中,重中之重就是roles和routes的内容、传递和判断,把两个变量的逻辑走通了就可以解决动态加载菜单的一切困难。

  • 24
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
动态路由是指路由表在运行时动态生成,而不是在编译时生成。在 Vue.js 中,可以使用 Vue Router 实现动态路由。下面是一个简单的步骤,可以帮助你搭建一个基于 Vue-admin-template动态路由。 1. 安装 Vue Router ```bash npm install vue-router --save ``` 2. 在 src/router/index.js 中引入 Vue Router,并创建一个路由实例 ```javascript import Vue from 'vue'; import Router from 'vue-router'; import Layout from '@/layout'; Vue.use(Router); export const constantRoutes = [ // 静态路由 { path: '/login', component: () => import('@/views/login/index'), hidden: true }, { path: '/404', component: () => import('@/views/404'), hidden: true }, { path: '/', component: Layout, redirect: '/dashboard', children: [{ path: 'dashboard', name: 'Dashboard', component: () => import('@/views/dashboard/index'), meta: { title: 'Dashboard', icon: 'dashboard' } }] } ]; const createRouter = () => new Router({ mode: 'history', // 启用 history 模式 scrollBehavior: () => ({ y: 0 }), routes: constantRoutes }); const router = createRouter(); export default router; ``` 3. 在 src/store/modules/permission.js 中创建一个动态路由生成函数 ```javascript import { constantRoutes } from '@/router'; /** * 递归过滤异步路由表,返回符合用户角色权限的路由表 * @param routes asyncRoutes * @param roles */ export function filterAsyncRoutes(routes, roles) { const res = []; routes.forEach(route => { const tmp = { ...route }; if (hasPermission(roles, tmp)) { if (tmp.children) { tmp.children = filterAsyncRoutes(tmp.children, roles); } res.push(tmp); } }); return res; } /** * 判断用户角色是否有权限访问该路由 * @param roles * @param route */ function hasPermission(roles, route) { if (route.meta && route.meta.roles) { return roles.some(role => route.meta.roles.includes(role)); } else { return true; } } const state = { routes: [], addRoutes: [] }; const mutations = { SET_ROUTES: (state, routes) => { state.addRoutes = routes; state.routes = constantRoutes.concat(routes); } }; const actions = { generateRoutes({ commit }, roles) { return new Promise(resolve => { let accessedRoutes; if (roles.includes('admin')) { accessedRoutes = asyncRoutes || []; } else { accessedRoutes = filterAsyncRoutes(asyncRoutes, roles); } commit('SET_ROUTES', accessedRoutes); resolve(accessedRoutes); }); } }; export default { namespaced: true, state, mutations, actions }; ``` 4. 在 src/router/index.js 中引入动态路由生成函数,并在路由实例中使用 ```javascript import Vue from 'vue'; import Router from 'vue-router'; import Layout from '@/layout'; import store from '@/store'; Vue.use(Router); export const constantRoutes = [ // 静态路由 { path: '/login', component: () => import('@/views/login/index'), hidden: true }, { path: '/404', component: () => import('@/views/404'), hidden: true }, { path: '/', component: Layout, redirect: '/dashboard', children: [{ path: 'dashboard', name: 'Dashboard', component: () => import('@/views/dashboard/index'), meta: { title: 'Dashboard', icon: 'dashboard' } }] } ]; const createRouter = () => new Router({ mode: 'history', // 启用 history 模式 scrollBehavior: () => ({ y: 0 }), routes: constantRoutes }); const router = createRouter(); // 刷新页面时重新生成动态路由 router.beforeEach(async(to, from, next) => { const hasRoles = store.getters.roles && store.getters.roles.length > 0; if (hasRoles) { next(); } else { try { // 获取用户角色信息 const { roles } = await store.dispatch('user/getInfo'); // 生成动态路由 const accessedRoutes = await store.dispatch('permission/generateRoutes', roles); // 添加动态路由 router.addRoutes(accessedRoutes); next({ ...to, replace: true }); } catch (error) { console.log(error); } } }); export function resetRouter() { const newRouter = createRouter(); router.matcher = newRouter.matcher; // reset router } export default router; ``` 以上是一个基于 Vue-admin-template动态路由搭建步骤,你可以根据自己的需求进行修改和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值