核心架构概览

  1. Vue Router 4 的核心架构由五大模块组成:

    1. Router 实例:路由管理器,负责整体路由控制;
    2. RouterHistory:处理浏览器历史记录,支持三种模式;
    3. RouterMatcher:路由匹配引擎,基于前缀树算法实现;
    4. NavigationGuard:导航守卫系统,控制路由访问权限;
    5. RouterView:路由视图组件,动态渲染匹配的组件;
  2. 下面是一个简化的架构图:

    ┌─────────────────────────────────────────────────────────┐
    │                      Router 实例                        │
    │  ┌───────────┐  ┌───────────────┐  ┌─────────────────┐  │
    │  │ 路由配置   │  │ 导航守卫队列   │  │ 全局钩子管理     │  │
    │  └───────────┘  └───────────────┘  └─────────────────┘  │
    └───────────────────────┬─────────────────────────────────┘
                            │
                            ▼
    ┌─────────────────────────────────────────────────────────┐
    │                    RouterMatcher (路由匹配器)           │
    │  ┌───────────┐  ┌───────────────┐  ┌─────────────────┐  │
    │  │ 路由记录树 │  │ 参数解析器     │  │ 路径生成器       │  │
    │  └───────────┘  └───────────────┘  └─────────────────┘  │
    └───────────────────────┬─────────────────────────────────┘
                            │
                            ▼
    ┌─────────────────────────────────────────────────────────┐
    │                    RouterHistory (路由历史)             │
    │  ┌───────────┐  ┌───────────────┐  ┌─────────────────┐  │
    │  │ HTML5 模式│  │ Hash 模式      │  │ 内存模式        │  │
    │  └───────────┘  └───────────────┘  └─────────────────┘  │
    └───────────────────────┬─────────────────────────────────┘
                            │
                            ▼
    ┌─────────────────────────────────────────────────────────┐
    │                    NavigationGuard (导航守卫)           │
    │  ┌───────────┐  ┌───────────────┐  ┌─────────────────┐  │
    │  │ 前置守卫   │  │ 解析守卫       │  │ 后置钩子         │  │
    │  └───────────┘  └───────────────┘  └─────────────────┘  │
    └───────────────────────┬─────────────────────────────────┘
                            │
                            ▼
    ┌─────────────────────────────────────────────────────────┐
    │                     RouterView (路由视图)               │
    │  ┌───────────┐  ┌───────────────┐  ┌─────────────────┐  │
    │  │ 视图渲染   │  │ 嵌套视图管理  │   │ 过渡动画        │  │
    │  └───────────┘  └───────────────┘  └─────────────────┘  │
    └─────────────────────────────────────────────────────────┘
    

核心源码实现 createRouter

  1. 下面是 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

打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 核心架构概览
  2. 2. 核心源码实现 createRouter
  3. 3. 核心源码实现 createRouter