核心架构概览
-
Vue Router 4 的核心架构由五大模块组成:
- Router 实例:路由管理器,负责整体路由控制;
- RouterHistory:处理浏览器历史记录,支持三种模式;
- RouterMatcher:路由匹配引擎,基于前缀树算法实现;
- NavigationGuard:导航守卫系统,控制路由访问权限;
- RouterView:路由视图组件,动态渲染匹配的组件;
-
下面是一个简化的架构图:
┌─────────────────────────────────────────────────────────┐ │ Router 实例 │ │ ┌───────────┐ ┌───────────────┐ ┌─────────────────┐ │ │ │ 路由配置 │ │ 导航守卫队列 │ │ 全局钩子管理 │ │ │ └───────────┘ └───────────────┘ └─────────────────┘ │ └───────────────────────┬─────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ RouterMatcher (路由匹配器) │ │ ┌───────────┐ ┌───────────────┐ ┌─────────────────┐ │ │ │ 路由记录树 │ │ 参数解析器 │ │ 路径生成器 │ │ │ └───────────┘ └───────────────┘ └─────────────────┘ │ └───────────────────────┬─────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ RouterHistory (路由历史) │ │ ┌───────────┐ ┌───────────────┐ ┌─────────────────┐ │ │ │ HTML5 模式│ │ Hash 模式 │ │ 内存模式 │ │ │ └───────────┘ └───────────────┘ └─────────────────┘ │ └───────────────────────┬─────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ NavigationGuard (导航守卫) │ │ ┌───────────┐ ┌───────────────┐ ┌─────────────────┐ │ │ │ 前置守卫 │ │ 解析守卫 │ │ 后置钩子 │ │ │ └───────────┘ └───────────────┘ └─────────────────┘ │ └───────────────────────┬─────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ RouterView (路由视图) │ │ ┌───────────┐ ┌───────────────┐ ┌─────────────────┐ │ │ │ 视图渲染 │ │ 嵌套视图管理 │ │ 过渡动画 │ │ │ └───────────┘ └───────────────┘ └─────────────────┘ │ └─────────────────────────────────────────────────────────┘
核心源码实现 createRouter
-
下面是 Vue Router 4 核心部分的简化源码实现
// src/router.ts import { reactive, readonly, ref, computed, watchEffect, InjectionKey } from 'vue' import { createRouterMatcher } from './matcher' import { HTML5History, HashHistory, MemoryHistory } from './history' // 路由配置类型 export interface RouteRecordRaw { path: string name?: string | symbol component: Component children?: RouteRecordRaw[] meta?: Record<string, any> beforeEnter?: NavigationGuard | NavigationGuard[] // 其他配置项... } // 规范化的路由位置 export interface RouteLocationNormalized { path: string name?: string | symbol params: Record<string, string | string[]> query: Record<string, string | string[] | null | undefined> hash: string fullPath: string meta: Record<string, any> matched: RouteRecordNormalized[] redirectedFrom?: RouteLocationNormalized } // 导航守卫函数类型 export type NavigationGuard = ( to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext ) => any // 创建路由实例 export function createRouter(options: RouterOptions) { const { history, routes, strict, sensitive, parseQuery, stringifyQuery } = options // 创建路由匹配器 (基于前缀树 Trie 算法) const matcher = createRouterMatcher(routes, { strict, sensitive, parseQuery, stringifyQuery }) // 当前路由状态 (响应式) const currentRoute = ref<RouteLocationNormalized>( matcher.resolve(history.location) ) // 路由实例 const router = { // 路由历史对象 history, // 获取所有路由记录 getRoutes() { return matcher.getRoutes() }, // 添加路由记录 addRoute(parentName, route) { matcher.addRoute(parentName, route) }, // 移除路由记录 removeRoute(name) { matcher.removeRoute(name) }, // 当前路由 (只读) currentRoute: readonly(currentRoute) as any, // 导航到新路由 async push(to) { return this._transitionTo(to) }, // 替换当前路由 async replace(to) { return this._transitionTo(to, { replace: true }) }, // 安装路由插件 install(app) { // 注册全局组件 app.component('RouterView', RouterView) app.component('RouterLink', RouterLink) // 提供路由实例 app.provide(routerKey, router) // 注册全局属性 app.config.globalProperties.$router = router Object.defineProperty(app.config.globalProperties, '$route', { get() { return router.currentRoute.value } }) // 启动路由监听 this.history.listen((to, from, info) => { this._transitionTo(to, { from, ...info }) }) // 初始化导航 this.history.setupListeners() }, // 核心导航过渡方法 async _transitionTo(to, options = {}) { // 解析目标路由 const targetLocation = normalizeLocation(to, this.currentRoute.value) const route = matcher.resolve(targetLocation) // 如果是相同路由则不进行导航 if (isSameRouteLocation(this.currentRoute.value, route)) { return } // 创建导航上下文 const navigation = { to: route, from: this.currentRoute.value, aborted: false, canceled: false, replaced: options.replace, // 其他导航状态... } try { // 执行导航守卫 await this._runNavigationGuards(navigation) // 更新当前路由 currentRoute.value = route // 更新浏览器历史 this.history.push(route.fullPath, options.replace) // 执行后置钩子 this._runAfterHooks(navigation) return true } catch (err) { // 处理导航失败 if (isNavigationFailure(err)) { return false } throw err } }, // 执行导航守卫队列 async _runNavigationGuards(navigation) { // 获取所有需要执行的守卫 const guards = this._resolveNavigationGuards(navigation) // 按顺序执行守卫 for (const guard of guards) { try { const result = await guard( navigation.to, navigation.from, (to) => { // 处理守卫的 next 函数 if (to === false) { navigation.aborted = true throw createNavigationFailure(navigation.to, navigation.from, NavigationFailureType.aborted) } else if (typeof to === 'string' || isRouteLocationRaw(to)) { navigation.redirectedFrom = navigation.to throw new NavigationRedirectError(to) } } ) // 处理守卫返回值 if (result === false) { navigation.aborted = true throw createNavigationFailure(navigation.to, navigation.from, NavigationFailureType.aborted) } else if (typeof result === 'string' || isRouteLocationRaw(result)) { navigation.redirectedFrom = navigation.to throw new NavigationRedirectError(result) } } catch (err) { // 处理重定向或取消 if (err instanceof NavigationRedirectError) { return this._transitionTo(err.location, { from: navigation.from, replace: true }) } throw err } } } } return router }
核心源码实现 createRouter
打赏作者
您的打赏是我前进的动力
微信
支付宝
Pinia 核心实现
上一篇
评论