Vue 路由问题:路由守卫与导航
Vue Router 提供了“路由守卫”机制,用于在用户切换页面(即导航)时执行逻辑判断。你可以用它实现登录验证、权限控制、页面加载前的数据预取等功能。掌握路由守卫的使用方法,是构建健壮单页应用的关键一步。
一、理解三种路由守卫类型
Vue Router 的路由守卫分为三类,按执行顺序依次为:
- 全局守卫:作用于整个应用的所有路由跳转。
- 路由独享守卫:只对某个特定路由生效。
- 组件内守卫:写在具体组件内部,仅影响该组件的路由行为。
每种守卫都可在“进入前”、“更新时”或“离开后”触发,但最常用的是“进入前”的拦截逻辑。
二、配置全局前置守卫(最常用)
全局前置守卫 router.beforeEach 在每次路由跳转之前执行,适合做统一权限校验。
- 打开你的路由配置文件(通常是
src/router/index.js或src/router.js)。 - 确保已创建
router实例(通过createRouter)。 - 调用
router.beforeEach方法,并传入一个回调函数,该函数接收三个参数:to(目标路由)、from(来源路由)、next(继续导航的函数)。
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import Profile from '@/views/Profile.vue'
const routes = [
{ path: '/', component: Home },
{ path: '/profile', component: Profile, meta: { requiresAuth: true } }
]
const router = createRouter({
history: createWebHistory(),
routes
})
router.beforeEach((to, from, next) => {
const isAuthenticated = !!localStorage.getItem('token') // 简单判断是否登录
if (to.meta.requiresAuth && !isAuthenticated) {
next('/') // 未登录且目标页需认证,则跳转首页
} else {
next() // 允许正常跳转
}
})
export default router
关键点:
next()必须被调用一次,否则导航会卡住。- 使用
meta字段标记路由是否需要认证(如meta: { requiresAuth: true }),这是一种约定俗成的做法。
三、设置路由独享守卫
如果你只想对某个路由做特殊处理,而不影响全局逻辑,可以使用路由独享守卫 beforeEnter。
- 在路由定义中,为目标路由添加
beforeEnter属性。 - 编写与全局守卫结构相同的回调函数。
const routes = [
{
path: '/admin',
component: () => import('@/views/Admin.vue'),
beforeEnter: (to, from, next) => {
const userRole = localStorage.getItem('role')
if (userRole === 'admin') {
next()
} else {
next('/unauthorized')
}
}
}
]
此守卫仅在进入 /admin 路径时触发,不影响其他页面。
四、使用组件内守卫
组件内守卫直接写在 Vue 组件中,适用于与组件强相关的导航逻辑(如离开页面前确认保存)。
- 在组件的
<script setup>或选项式 API 中,定义以下三个可选的守卫函数:beforeRouteEnter:进入该组件对应路由前调用(此时组件实例还未创建)。beforeRouteUpdate:当前路由改变但组件复用时调用(如动态路由/user/1→/user/2)。beforeRouteLeave:离开当前路由前调用。
<script setup>
import { onBeforeRouteLeave } from 'vue-router'
onBeforeRouteLeave((to, from, next) => {
const answer = window.confirm('你有未保存的内容,确定要离开吗?')
if (answer) {
next()
} else {
next(false) // 取消导航
}
})
</script>
<template>
<div>编辑页面</div>
</template>
注意:在
<script setup>中,需从vue-router导入对应的组合式函数;若使用选项式 API,则直接在组件对象中定义同名方法即可。
五、正确使用 next() 函数
next() 是控制导航流程的核心,不同调用方式产生不同效果:
| 调用方式 | 效果说明 |
|---|---|
next() |
正常进入目标路由 |
next(false) |
中断当前导航,留在原页面 |
next('/') |
中断当前导航,重定向到指定路径 |
next({ name: 'Login' }) |
通过命名路由跳转 |
务必避免在守卫中多次调用 next(),这会导致不可预期的行为。
六、处理异步逻辑(如 API 验证)
当守卫中需要发起网络请求(例如验证 token 是否有效),必须等待异步操作完成后再调用 next()。
router.beforeEach(async (to, from, next) => {
if (to.meta.requiresAuth) {
try {
const response = await fetch('/api/validate-token')
if (response.ok) {
next()
} else {
next('/login')
}
} catch (error) {
next('/login')
}
} else {
next()
}
})
关键:将守卫回调声明为
async函数,并用await等待结果,确保next()在异步完成后才被调用。
七、避免常见错误
- 忘记调用
next():导致页面卡死,白屏无响应。 - 在守卫中直接修改路由:不要在
beforeEach里调用router.push(),应使用next('/path')。 - 滥用全局守卫:简单逻辑优先使用组件内守卫或路由独享守卫,保持全局逻辑简洁。
- 忽略导航重复问题:如果
next()传入的路径与当前路径相同,Vue Router 会抛出警告。可通过判断to.path !== from.path避免。
八、完整导航解析流程(文字描述)
当你触发一次路由跳转(如点击 <router-link> 或调用 router.push()),Vue Router 按以下顺序执行:
- 触发失活组件的
beforeRouteLeave守卫。 - 调用全局
beforeEach守卫。 - 触发目标路由的
beforeEnter守卫(如果有)。 - 解析异步路由组件(如
() => import(...))。 - 触发新组件的
beforeRouteEnter守卫。 - 导航被确认,更新 URL。
- 触发全局
afterEach钩子(无next,仅用于日志、埋点等)。 - 新组件实例创建完成,
beforeRouteEnter中可通过回调访问组件实例。
此流程确保了权限、数据、UI 更新的有序执行。

暂无评论,快来抢沙发吧!