Vue-Router全局路由钩子(导航守卫)使用
旧版的全局路由钩子的使用方法
router.beforeEach((to, from, next) => {
if (isLogin() && to.name === 'Login') {
next('/')
} else if (!isLogin() && to.name !== 'Login') {
next({ name: 'Login' })
} else {
next()
}
})
新版全局路由钩子的使用方法
router.beforeEach((to, from) => {
if (isLogin() && to.name === 'Login') {
return '/'
}
if (!isLogin() && to.name !== 'Login') {
return {
name: 'Login',
}
}
return true
})
可见新版全局路由钩子并不需要next方法来进行重定向,即使next方法仍可使用,可能在未来会被废弃,使用return 会更加适应新版本的变化,而且可以让代码更加清晰。
在全局路由钩子函数中动态添加路由
动态路由的添加
在实现后台权限动态渲染功能的时候,往往需要在全局路由钩子中动态添加路由。在vue-router V3版本中,使用router.addRoutes
来批量添加路由,但是在V4版本中这个api被废弃了,需要使用router.addRoute
方法,循环添加路由。添加了路由,也仅仅是注册了这个路由而已,如果需要当前进入的路由和新添加的路由匹配,还需要使用next({...to, replace: true})
, 重定向到这个路由,才能渲染这个新路由对应的页面。
import { createRouter, createWebHistory } from 'vue-router'
import constantRoutes from './constant-routes';
import { getDynamicRoutes } from '@/api/index';
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
redirect: '/home'
},
...constantRoutes // 静态路由包含了404页面,当所有页面都匹配不上时,会重定向到404
]
})
// 是否已经添加动态路由
let isAddRoutes = false
router.beforeEach(async (to, from, next) => {
if (!isAddRoutes) {
isAddRoutes = true
const dynamicRoutes = await getDynamicRoutes()
dynamicRoutes.forEach(route => {
router.addRoute({
path: route.path,
name: route.name,
component: route.component
})
})
next({ ...to, replace: true })
} else {
next()
}
})
export default router
解决第一次进入动态路由页面会渲染404页面的问题
使用以上方法动态添加路由,会导致第一次直接进入动态路由时,会渲染404页面,因为当第一次进入全局路由钩子时,动态路由还没加载完毕,匹配不到,优先匹配静态路由,就会直接渲染路由为*
的404页面。
以前的做法,是在批量添加动态路由的最后,最后再动态添加404页面的路由,就可以给等待动态路由添加完毕,再渲染页面。
// 是否已经添加动态路由
let isAddRoutes = false
router.beforeEach(async (to, from, next) => {
if (!isAddRoutes) {
isAddRoutes = true
const dynamicRoutes = await getDynamicRoutes()
dynamicRoutes.forEach(route => {
router.addRoute({
path: route.path,
name: route.name,
component: route.component
})
})
// 手动添加404页面
router.addRoute({
path: '/:pathMatch(.*)*',
name: 'not-found',
component: () => import('../views/NotFoundView.vue')
})
next({ ...to, replace: true })
} else {
next()
}
})
这样,貌似就没有问题了,页面能够正常渲染,但是控制台会出现警告
这是因为,在等待路由加载的过程中,当前进入的路由是动态的,而我们的动态路由配置尚未加载完毕,未匹配中任何的路由,to.matched为空,所以vue-router就抛出了这个警告。
解决报警问题
根据上面的分析得出,是因为第一次进入动态路由的页面,动态路由正在加载中,当前路由未匹配到任何的已配置路由,所以会报警。
那么解决的办法,就是不在全局路由钩子动态添加404页面,而是写在静态路由配置中。当第一次从动态路由中进入,由于存在404页面,因为404的页面路由是*
,就相当于匹配到了路由,不会出现报警.
虽然这时候匹配到了404页面,但是还没走到渲染404页面的逻辑,因为next还没执行,这时候再等待动态路由加载完毕再使用next重定向到进入的动态路由,即可避免报警的问题。
export default [
{
path: '/home',
name: 'home',
component: () => import('../views/HomeView.vue')
},
// 可以在静态路由中写死该配置
{
path: '/:pathMatch(.*)*',
name: 'not-found',
component: () => import('../views/NotFoundView.vue')
}
]
// 是否已经添加动态路由
let isAddRoutes = false
router.beforeEach(async (to, from, next) => {
if (!isAddRoutes) {
isAddRoutes = true
const dynamicRoutes = await getDynamicRoutes()
dynamicRoutes.forEach(route => {
router.addRoute({
path: route.path,
name: route.name,
component: route.component
})
})
// 返回to.fullPath,当添加完所有的动态路由后,触发重定向
next(to.fullPath)
} else {
next()
}
})
使用V4新版的写法,我们可以将next函数,换成return,代码会更加清晰
// 判断否已经添加动态路由,避免重复添加
let isAddRoutes = false
router.beforeEach(async (to, from) => {
if (!isAddRoutes) {
isAddRoutes = true
const dynamicRoutes = await getDynamicRoutes()
dynamicRoutes.forEach(route => {
router.addRoute({
path: route.path,
name: route.name,
component: route.component
})
})
// 返回to.fullPath,当添加完所有的动态路由后,触发重定向
return to.fullPath
}
return true
})
总结
新版的Vue-Router动态添加路由主要的两个坑点:
- 在静态路由中增加404页面,会导致从动态路由进入时会渲染404页面组件的内容
- 在动态添加路由的最后再添加404页面,会触发vue-router报警问题
解决方法:
- 404页面在静态路由中添加
- 添加动态路由后,直接重定向到当前进入路由的fullPath,使当前路由与动态路由匹配,渲染对应的页面