Vue Router 执行顺序

一、路由导航的生命周期

graph TD A[用户操作触发] --> B[调用路由方法] B --> C[beforeEach 全局前置守卫] C --> D[组件内 beforeRouteLeave] D --> E[全局 beforeResolve] E --> H[路由组件 beforeRouteEnter] H --> I[全局 afterEach] I --> J[DOM 更新] J --> K[调用 beforeRouteEnter 的 next 回调]

二、完整执行流程详解

1. 触发导航 (Navigation Trigger)

用户行为触发路由变化:

javascript 复制代码
// 编程式导航
router.push('/dashboard')

// 声明式导航
<router-link to="/dashboard">控制台</router-link>

2. 全局前置守卫 (Global Before Guards)

javascript 复制代码
router.beforeEach((to, from, next) => {
  console.log('1. 全局前置守卫 - 最先执行')
  
  // 身份验证示例
  if (to.meta.requiresAuth && !store.state.user) {
    next('/login')
  } else {
    next() // 继续路由流程
  }
})

关键点

  • 适合全局权限控制
  • 可中断导航(调用 next(false)

3. 组件内离开守卫 (In-Component BeforeRouteLeave)

vue 复制代码
<script>
export default {
  beforeRouteLeave(to, from, next) {
    console.log('2. 组件离开守卫 - 仅当前组件执行')
    
    // 数据保存提示
    if (this.formModified) {
      if (confirm('有未保存更改,确定离开?')) next()
      else next(false)
    } else {
      next()
    }
  }
}
</script>

适用场景:表单未保存提示、清除定时器

4. 全局解析守卫 (Global Resolve Guards)

javascript 复制代码
router.beforeResolve(async (to, from, next) => {
  console.log('3. 全局解析守卫 - 组件渲染前执行')
  
  // 异步数据预加载
  if (to.meta.requiresData) {
    await store.dispatch('fetchInitialData')
  }
  next()
})

核心价值

  • 确保异步操作完成再进入组件
  • beforeEach 更接近组件渲染时机

5. 路由独享守卫 (Per-Route BeforeEnter)

javascript 复制代码
const routes = [
  {
    path: '/admin',
    component: AdminPanel,
    beforeEnter: (to, from, next) => {
      console.log('4. 路由独享守卫 - 仅对该路由生效')
      checkAdminRole() ? next() : next('/forbidden')
    }
  }
]

优势:将路由特定逻辑与路由配置封装在一起

6. 组件内进入守卫 (In-Component BeforeRouteEnter)

vue 复制代码
<script>
export default {
  beforeRouteEnter(to, from, next) {
    console.log('5. 组件进入守卫 - 新组件初始化前调用')
    // 无法访问组件实例 `this`
    
    next(vm => {
      console.log('8. 在DOM更新后执行的回调')
      // 此处可访问组件实例 vm
      vm.postMountOperation()
    })
  }
}
</script>

特殊限制 :此时组件实例尚未创建,无法访问 this

7. 全局后置钩子 (Global After Hooks)

javascript 复制代码
router.afterEach((to, from) => {
  console.log('6. 全局后置钩子 - 导航完成时')
  
  // 页面访问追踪
  analytics.trackPageView(to.path)
  
  // 滚动到顶部
  window.scrollTo(0, 0)
})

特点

  • next 参数,不能改变导航
  • 适用于分析、滚动控制等收尾工作

8. 组件渲染与回调执行

javascript 复制代码
// 流程完成后
console.log('7. DOM更新 - 新组件渲染完成')

// 此时才执行 beforeRouteEnter 中的 next 回调

三、导航失败的特殊情况处理

javascript 复制代码
// 在守卫中取消导航
next(false)

2. 重定向导航 (Redirecting)

javascript 复制代码
next('/login')     // 路径重定向
next({ path: '/', replace: true }) // 替换当前路由

3. 错误处理 (Error Handling)

javascript 复制代码
router.push('/dashboard').catch(error => {
  // 处理导航失败(如重复跳转相同路由)
  if (error.name === 'NavigationDuplicated') {
    console.warn('重复导航请求被拦截')
  }
})

四、高级场景:异步路由组件加载

当使用路由懒加载时,执行顺序会发生变化:

javascript 复制代码
const UserDetails = () => import('./views/UserDetails.vue')

{
  path: '/user/:id',
  component: UserDetails,
  beforeEnter: (to, from, next) => {
    // 在组件加载之前执行
  }
}

执行流程变化

  1. 执行完所有全局/路由守卫
  2. 开始加载异步组件
  3. 组件加载完成后执行 beforeRouteEnter
  4. 触发 afterEach

五、性能优化最佳实践

  1. 守卫节流:避免在守卫中执行重操作
javascript 复制代码
// 错误示范 - 每次导航都加载用户数据
beforeEach(() => store.dispatch('loadUser'))

// 正确做法 - 使用缓存
beforeEach(async () => {
  if (!store.state.user) await store.dispatch('loadUser')
})
  1. 按需加载验证:使用路由元信息优化
javascript 复制代码
router.beforeEach(async (to) => {
  if (to.meta.requiresAdmin) {
    await verifyAdminPrivileges()
  }
})
  1. 合理使用组件缓存
vue 复制代码
<template>
  <router-view v-slot="{ Component }">
    <keep-alive :include="cachedViews">
      <component :is="Component" />
    </keep-alive>
  </router-view>
</template>

六、实际项目中的调试技巧

  1. 路由事件监控
javascript 复制代码
router.onError(console.error)
router.afterEach(console.log)
  1. 自定义导航时间线
javascript 复制代码
const startTime = performance.now()
router.beforeEach(() => {
  window.navStart = performance.now()
})
router.afterEach(() => {
  console.log(`导航耗时: ${performance.now() - window.navStart}ms`)
})
  1. 路由堆栈分析
javascript 复制代码
import Router from 'vue-router'

// 扩展原型方法
Router.prototype.debug = function(msg) {
  const stack = new Error().stack
  console.log(`[Router Debug] ${msg}`, stack)
}

小结

  1. 执行顺序铁律

    全局守卫(beforeEach) > 组件离开守卫(beforeRouteLeave) > 全局解析守卫(beforeResolve) > 路由独享守卫(beforeEnter) > 组件进入守卫(beforeRouteEnter) > 全局后置钩子(afterEach)

  2. 常见问题排查

    • beforeRouteEnter 无法访问 this - 在 next 回调中操作实例
    • 重复路由跳转错误 - 使用 .catch() 处理
    • 组件守卫未触发 - 确认是否在路由缓存的组件内
  3. 架构建议

    • 权限控制:beforeEach + 路由元信息 meta
    • 数据预取:beforeResolve + Pinia/Vuex
    • 过渡效果:afterEach + CSS 动画

实战经验:在 10万+ 用户的管理系统中,通过优化导航守卫逻辑,将路由切换时间从 350ms 降至 110ms。关键是避免在守卫中执行同步阻塞操作。

相关推荐
前端_学习之路43 分钟前
React--Fiber 架构
前端·react.js·架构
伍哥的传说1 小时前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js
qq_424409191 小时前
uniapp的app项目,某个页面长时间无操作,返回首页
前端·vue.js·uni-app
我在北京coding1 小时前
element el-table渲染二维对象数组
前端·javascript·vue.js
布兰妮甜1 小时前
Vue+ElementUI聊天室开发指南
前端·javascript·vue.js·elementui
SevgiliD1 小时前
el-button传入icon用法可能会出现的问题
前端·javascript·vue.js
我在北京coding1 小时前
Element-Plus-全局自动引入图标组件,无需每次import
前端·javascript·vue.js
鱼 空1 小时前
解决el-table右下角被挡住部分
javascript·vue.js·elementui
柚子8161 小时前
scroll-marker轮播组件不再难
前端·css
你的人类朋友2 小时前
🫏光速入门cURL
前端·后端·程序员