赞
踩
思路:
- 创建全局路由前置守卫
- 利用``vuex``请求用户权限点
- 动态添加这些菜单权限路由
- 合理利用`next`放行或执行新的导航
- 不存在的路由重定向至404页
需特别注意的点:
- 重新登录后一定要清空前端路由表,否则仍能访问没有权限的路由 (我的项目中所有的动态路由都是home路由的子路由。自定义方法`resetRouter` )
- 注意要将已配置的静态路由设为白名单
- 关于 ``next({ ...to, replace: true })`` 主要是解决了刷新后导致白屏的问题,最后详细说明
- vue3中只有`addRoute` (`addRoutes`被移除)
第一步先定义静态路由表,需包括 首页,404页,登录页
// router/index.js import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router' const routes: Array<RouteRecordRaw> = [ { path: '/', name: 'home', component: () => import('@/views/index.vue') }, { path: '/404', name: 'NotFound', component: () => import('@/components/sysCas/SysCas404.vue') }, { path: '/login', name: 'login', component: () => import('@/views/login/index.vue') } ] const router = createRouter({ history: createWebHashHistory(), routes }) // 由于这个项目的其他菜单均为home这个路由的子路由,所以只重置了home export function resetRouter() { // 通过添加一个名称冲突的路由 删除添加的路由 router.addRoute({ path: '/', name: 'home', component: () => import('@/views/index.vue') }) } export default router
第二步利用vuex
管理状态
import { GetUserAuth } from '@/api/loginApi' export default { namespaced: true, state: { dynamicCreateRoute: false, // 异步创建路由标识 routeAuth: [] // 用户路由表存储点 }, mutations: { updateDynamicCreateRoute: function(state: any, flag: Boolean) { state.dynamicCreateRoute = flag }, setRouteAuth: function(state: any, routeAuth: Array<Object>) { state.routeAuth = routeAuth } }, actions: { // getRouteAuth 为获取登录用户菜单权限的接口 getRouteAuth({ commit, state }: any, userName: string) { return new Promise((resolve, reject) => { GetUserAuth(userName).then(res => { commit('setRouteAuth', res) resolve(res) }) }) } } }
第三部创建全局路由前置守卫
// 这是接口返回的菜单数据格式
interface MenuVo {
id: string,
pid: string,
name: string, // 路由名 如:sysManager
path: string, // 路由 如:/sysManager
component: any // 组件位置 如:/sysManager/index.vue
}
// 全局路由前置守卫 import store from '@/store' import { getToken } from '@/utils/auth' const whiteList = ['/login', '/', '/404'] // 白名单 router.beforeEach(async (to, from, next) => { const token = getToken() // 获取登录状态 // case1: 已登陆且url导向了登录页 则重定向至首页 if (token && to.path === '/login') { next('/') return } // case2: 未登录 放行白名单 if (!token) { whiteList.indexOf(to.path) !== -1 ? next() : next(`/login?redirect=${to.path}`) return } /** * @description: 已登陆 */ if (token) { const dynamicCreateRoute = store.state.core.dynamicCreateRoute // 异步创建路由标识避免重复请求 // TODO: 处理所有页面权限 包括404页面等 if (!dynamicCreateRoute) { store.commit('core/updateDynamicCreateRoute', true) // 分发获取登录者拥有的菜单权限 routeAuth await store.dispatch('core/getRouteAuth', store.state.user.user.login_name) const routeAuth = store.state.core.routeAuth if (routeAuth.length === 0) { next('/') return } routeAuth.forEach((menu: MenuVo) => { const routeOne: any = { path: menu.path, name: menu.name, component: () => import(`./views${menu.component}`) } if (!router.hasRoute(menu.name)) router.addRoute('home', routeOne) // 插入菜单权限 }) // 递归调用{ ...to, replace: true } 由于刷新页面的时候动态路由会刷新掉,然后动态路由会重新加载,而匹配路由会在加载路由之前,所以会导致空白页 next({ ...to, replace: true }) } else { next() } } // 必须有 否则访问不存在路由不会跳转404 if (!router.hasRoute('redirect404')) router.addRoute({path: '/:catchAll(.*)', name: 'redirect404', redirect: '/404'}) console.log(router.getRoutes()) // 查看当前所有路由 })
next()
next()
即为放行,但next('/login')
、next({ ...to, replace: true })
则不只是简单的将路由切到其参数。next()有参数时则表示**中断当前导航,执行新的导航**,意味着会执行一遍新的
beforeEach,新的
beforeEach的参数
to则是
next()`的参数。
例如:next('/login')
则会转化为beforeEach('/login', from, next)
被执行。
这意味着,如果你的全局守卫中没有正确的next()
将会陷入死循环
再说next({ ...to, replace: true })
通过addRoute
动态添加的路由如果刚添加完就立刻放行,此时addRoute
还没有执行结束,因此找不到刚添加的路由,就会导致白屏,因此需要重新访问一遍路由才行
next({...to})
则能够递归调用beforeEach
直到找到对应的路由。
replace:true
则是防止在递归调用期间用户点击浏览器的后退按钮产生错误。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。