github编辑

Vue router源码解析(todo)

Vue-router源码解析

status: Draft tags: Vue, 源码解析 Created time: March 7, 2023 10:57 AM emoji: https://vuejs.org/logo.svg

VueRouter类

VueRouter

三种mode

实现导航

一次导航的完整步骤

vue-router一次完整的导航包含以下步骤:

  1. 导航被触发。

  2. 在失活的组件里调用 beforeRouteLeave 守卫。

  3. 调用全局的 beforeEach 守卫。

  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。

  5. 在路由配置里调用 beforeEnter

  6. 解析异步路由组件。

  7. 在被激活的组件里调用 beforeRouteEnter

  8. 调用全局的 beforeResolve 守卫 (2.5+)。

  9. 导航被确认。

  10. 调用全局的 afterEach 钩子。

  11. 触发 DOM 更新。

  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

实现push

前端浏览器跳转页面通常有两种方式,代码跳转和浏览器跳转,代码跳转包含调用this.$router.push() 和点击<router-link>组件,浏览器跳转则是点击浏览器特定按钮,例如前进和后退按钮进行跳转。

无论是代码跳转还是浏览器跳转,其最终都调用了transitionTo函数,下面以HTML5History模式为例。

transitionTo函数

transitionTo位于类History,它是HashHistory、HTML5History 、AbstractHistory的父类。

transitionTo会再调用confirmTransition 函数来确定是否跳转路由,并传递一个onComplete函数作为完成时的回调。

confirmTransition

confirmTransition 函数将所有要执行的函数存储到队列中,以确保执行顺序的正确。最初执行:

runQueue 函数会按顺序将这些守卫函数传入iterator 函数中执行,当用户在导航守卫中调用next()调转其他路由时,又会重新调用push跳转到目标路由。

在confirmTransition函数中调用runQueue时,又传入了一个回调函数,以便queue执行完毕后执行。

在这个函数中又会以相同的方式执行

  • 激活路由的beforeRouteEnter守卫

  • 全局beforeResolve守卫

最后又调用了

这里的onComplete来自transitionTo函数:

updateRoute函数执行的过程中会调用this.cb(route) ,这里的cb函数来自前面VueRouter类的init方法中:

由于app._route是响应式的,改变app._route时就会导致页面重新渲染,也就是触发了DOM更新。

也就是说在这一过程中做了:

  • 更新路由

  • 执行用户onComplete函数

  • 确定路由(ensureURL)

  • 执行全局beforeEach守卫

  • 触发 DOM 更新。

为什么app._route = route先执行,但是DOM却在后面才触发更新呢?这是因为Vue组件渲染是异步的,由一个异步调度系统控制。

最后,调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

这里使用nextTick的原因也同样是因为要延迟到DOM更新后再执行。

至此,导航解析核心流程执行完毕:

  1. 导航被触发。

  2. 在失活的组件里调用 beforeRouteLeave 守卫。

  3. 调用全局的 beforeEach 守卫。

  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。

  5. 在路由配置里调用 beforeEnter

  6. 解析异步路由组件。

  7. 在被激活的组件里调用 beforeRouteEnter

  8. 调用全局的 beforeResolve 守卫 (2.5+)。

  9. 导航被确认。

  10. 调用全局的 afterEach 钩子。

  11. 触发 DOM 更新。

  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

监听浏览器事件

组件