前端路由守卫:掌控页面跳转的 “守门人”

在前端单页应用(SPA)中,路由系统是实现页面切换的核心。而导航守卫,就是路由系统的 "守门人",它能在路由跳转的各个阶段介入,实现权限控制、页面拦截、数据预加载等关键功能。本文将以 Vue Router 为例,全面拆解导航守卫的原理、分类和实战场景。

一、导航守卫的核心作用

单页应用的路由跳转是客户端行为,不会触发浏览器的页面刷新。导航守卫的本质,是在路由跳转的生命周期中植入钩子函数,让开发者可以:

  • 权限校验:比如未登录用户拦截到登录页、普通用户禁止访问管理员路由。
  • 数据预加载:进入页面之前请求数据,避免页面渲染后出现空白。
  • 页面拦截:比如表单未提交时,阻止用户跳转并提示保存。
  • 路由跳转日志:记录用户的页面访问轨迹,用于埋点分析。

二、导航守卫的分类与使用

Vue Router 中的导航守卫分为 3 大类,覆盖了路由跳转的完整流程:

  • 全局守卫
  • 路由独享守卫
  • 组件内守卫

2.1 全局守卫

全局守卫会作用于所有路由 ,通常在路由实例初始化时定义,分为 beforeEach、beforeResolve、afterEach 三个钩子。

(1)router.beforeEach:全局前置守卫

这是最常用的全局守卫,在路由跳转前 触发,适合做全局权限控制。

语法:

javascript

运行

复制代码
const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // to: 即将要进入的目标路由对象
  // from: 当前正要离开的路由对象
  // next: 必须调用该方法,才能进入下一个钩子
  next() // 放行
  // next(false) // 中断导航
  // next('/login') // 跳转到指定路由
  // next({ path: '/login', replace: true }) // 跳转且不留下历史记录
})

实战场景:登录校验

javascript

运行

复制代码
router.beforeEach((to, from, next) => {
  // 判断目标路由是否需要登录权限
  if (to.meta.requiresAuth) {
    const token = localStorage.getItem('token')
    if (token) {
      next() // 已登录,放行
    } else {
      next('/login') // 未登录,跳转到登录页
    }
  } else {
    next() // 不需要权限,直接放行
  }
})

// 路由配置中添加 meta 字段标记权限
const routes = [
  {
    path: '/dashboard',
    component: Dashboard,
    meta: { requiresAuth: true } // 需要登录
  },
  { path: '/login', component: Login }
]
(2)router.beforeResolve:全局解析守卫

在所有组件内守卫和异步路由组件解析之后 触发,与 beforeEach 类似,但它会等待所有异步操作完成后再执行。

(3)router.afterEach:全局后置钩子

在路由跳转完成后 触发,它没有 next 函数,因为此时导航已经完成,只能用于页面埋点、滚动条重置等操作。

javascript

运行

复制代码
router.afterEach((to, from) => {
  // 记录页面访问日志
  console.log(`用户从 ${from.path} 跳转到 ${to.path}`)
  // 重置页面滚动条到顶部
  window.scrollTo(0, 0)
})

2.2 路由独享守卫

路由独享守卫只作用于单个路由 ,在路由配置中通过 beforeEnter 定义,适合对特定路由进行拦截。

语法与实战:

javascript

运行

复制代码
const routes = [
  {
    path: '/admin',
    component: Admin,
    meta: { requiresAuth: true },
    beforeEnter: (to, from, next) => {
      // 仅对 /admin 路由生效的权限校验
      const isAdmin = localStorage.getItem('role') === 'admin'
      if (isAdmin) {
        next()
      } else {
        next('/403') // 无权限跳转到 403 页面
      }
    }
  }
]

2.3 组件内守卫

组件内守卫是定义在组件内部 的钩子,用于监听组件自身的路由跳转,分为 beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave。

(1)beforeRouteEnter:进入组件前触发

注意 :此时组件实例还未创建(this 为 undefined),若要访问组件实例,需通过 next 的回调函数。

javascript

运行

复制代码
export default {
  beforeRouteEnter (to, from, next) {
    // 通过 next 回调访问组件实例
    next(vm => {
      // vm 就是组件实例
      vm.fetchData() // 进入组件前预加载数据
    })
  }
}
(2)beforeRouteUpdate:路由参数更新时触发

当路由参数变化但组件被复用(比如 /user/:id 从 /user/1 跳转到 /user/2)时触发,可用于更新组件数据。

javascript

运行

复制代码
export default {
  beforeRouteUpdate (to, from, next) {
    // 更新路由参数对应的用户信息
    this.userId = to.params.id
    this.fetchUserInfo()
    next()
  }
}
(3)beforeRouteLeave:离开组件时触发

适合做页面离开拦截,比如表单未提交时提示用户。

javascript

运行

复制代码
export default {
  data () {
    return {
      formData: {},
      isDirty: false // 标记表单是否修改
    }
  },
  beforeRouteLeave (to, from, next) {
    if (this.isDirty) {
      const confirm = window.confirm('表单未保存,确定离开吗?')
      if (confirm) {
        next()
      } else {
        next(false) // 取消导航
      }
    } else {
      next()
    }
  }
}

三、导航守卫的执行顺序

当一个路由跳转触发时,各类守卫的执行顺序是固定的,遵循 "前置 → 解析 → 组件内 → 后置" 的流程:

  1. 全局前置守卫 beforeEach
  2. 路由独享守卫 beforeEnter
  3. 组件内守卫 beforeRouteEnter
  4. 全局解析守卫 beforeResolve
  5. 导航完成
  6. 全局后置钩子 afterEach
  7. 组件内守卫 beforeRouteEnter 的 next 回调

四、常见问题与注意事项

4.1 不要忘记调用 next

在 beforeEach、beforeEnter 等带 next 的守卫中,必须调用 next() 才能继续导航,否则会导致路由跳转卡住。

4.2 避免无限循环

如果在守卫中跳转到自身路由,会触发无限循环,比如:

javascript

运行

复制代码
// 错误示例:会无限触发 beforeEach
router.beforeEach((to, from, next) => {
  if (to.path !== '/login') {
    next('/login') // 若 /login 也触发该守卫,会无限循环
  }
})

解决方法:添加条件判断,避免重复跳转。

4.3 异步操作的处理

如果在守卫中执行异步操作(比如请求接口校验权限),需要在异步回调中调用 next:

javascript

运行

复制代码
router.beforeEach((to, from, next) => {
  // 异步校验权限
  checkPermission().then(res => {
    if (res) next()
    else next('/403')
  })
})

五、总结

导航守卫是前端路由系统的核心能力,它让开发者能够精准掌控路由跳转的每一个环节。无论是 Vue Router 还是 React Router(通过 useNavigate、useLocation 等钩子实现类似功能),导航守卫的设计思想都是一致的 ------在生命周期中植入钩子,实现业务逻辑的灵活介入。

掌握导航守卫的分类和执行顺序,就能轻松应对权限控制、数据预加载等常见需求,让单页应用的路由跳转更安全、更智能。

👉 **觉得有用的点点关注谢谢~**

相关推荐
object not found41 分钟前
WooCommerce 接入 KPay 后订单完成页不显示订单信息:returnUrl 动态参数问题解决
前端·wordpress·独立站支付
yume_sibai1 小时前
04-Nginx部署实战完全指南(前端部署 + 后端代理 + 监控告警 + 故障排查)
运维·前端·nginx
data analyse 4561 小时前
数据合规的同意记录怎么留存?
前端·人工智能·数据分析
linux_cfan1 小时前
videojs v10 源代码系列解读:35 · HLS 解析器:multivariant 与 media playlist
前端·javascript·音视频
IT_陈寒1 小时前
Redis键过期失效?这个坑我踩得明明白白
前端·人工智能·后端
web打印社区1 小时前
汽修 / 4S 店:维修工单、结算单网页怎么静默出纸
开发语言·前端·javascript·chrome·ecmascript
liangshanbo12151 小时前
Webpack的分包策略面试题
前端·webpack·node.js
ttwuai2 小时前
Golang Web后台管理框架推荐:Gin、GoFrame与数据面板项目怎么分
前端·golang·gin
广州华水科技2 小时前
北斗GNSS变形监测系统在水库安全监测中的应用与优势
前端