Skip to content

Vue Router 架构分析

整体架构

Vue Router 采用基于路由匹配和导航的架构,通过路由器、路由记录和导航守卫管理应用路由。

┌─────────────────────────────────────────────┐
│              Vue Router                    │
├─────────────────────────────────────────────┤
│  1. Router (路由器)                         │
│     - Route Matching (路由匹配)             │
│     - Navigation (导航)                     │
│     - History Management (历史管理)        │
├─────────────────────────────────────────────┤
│  2. Route Record (路由记录)                  │
│     - Path (路径)                           │
│     - Component (组件)                      │
│     - Children (子路由)                    │
├─────────────────────────────────────────────┤
│  3. Navigation Guards (导航守卫)            │
│     - Global Guards (全局守卫)              │
│     - Route Guards (路由守卫)               │
│     - Component Guards (组件守卫)           │
└─────────────────────────────────────────────┘

核心组件

1. Router

路由器负责路由匹配和导航。

职责:

  • 路由匹配
  • 导航管理
  • 历史管理

关键方法:

javascript
class Router {
  constructor(options) {
    this.routes = options.routes || []
    this.currentRoute = null
    this.history = createHistory(options.mode)
  }
  
  // 初始化路由
  init(app) {
    // 初始化逻辑
  }
  
  // 导航到指定路由
  push(location) {
    this.history.push(location)
  }
  
  // 替换当前路由
  replace(location) {
    this.history.replace(location)
  }
  
  // 返回上一页
  go(n) {
    this.history.go(n)
  }
}

优势:

  • 灵活:支持多种路由模式
  • 强大:支持嵌套路由
  • 可扩展:支持自定义路由

2. Route Record

路由记录表示单个路由配置。

职责:

  • 存储路由配置
  • 管理子路由
  • 匹配路径

关键方法:

javascript
class RouteRecord {
  constructor(record) {
    this.path = record.path
    this.component = record.component
    this.name = record.name
    this.children = record.children || []
    this.props = record.props
    this.meta = record.meta || {}
  }
  
  // 添加子路由
  addChild(record) {
    this.children.push(new RouteRecord(record))
  }
  
  // 匹配路径
  match(path) {
    // 匹配逻辑
  }
}

优势:

  • 简单:简单的路由配置
  • 灵活:支持嵌套路由
  • 可扩展:支持自定义属性

3. Navigation Guards

导航守卫用于控制导航流程。

职责:

  • 全局守卫
  • 路由守卫
  • 组件守卫

关键方法:

javascript
// 全局前置守卫
router.beforeEach((to, from, next) => {
  // 守卫逻辑
  next()
})

// 全局后置钩子
router.afterEach((to, from) => {
  // 钩子逻辑
})

// 路由独享守卫
{
  path: '/user',
  component: User,
  beforeEnter: (to, from, next) => {
    // 守卫逻辑
    next()
  }
}

// 组件内守卫
export default {
  beforeRouteEnter(to, from, next) {
    // 守卫逻辑
    next()
  },
  beforeRouteUpdate(to, from, next) {
    // 守卫逻辑
    next()
  },
  beforeRouteLeave(to, from, next) {
    // 守卫逻辑
    next()
  }
}

优势:

  • 灵活:支持多种守卫类型
  • 强大:支持导航控制
  • 可组合:守卫可以组合使用

路由匹配

路径匹配

javascript
function matchPath(path, routePath) {
  // 简单匹配
  if (path === routePath) {
    return { path, params: {} }
  }
  
  // 动态参数匹配
  const paramNames = []
  const regexPath = routePath.replace(/:([^/]+)/g, (_, name) => {
    paramNames.push(name)
    return '([^/]+)'
  })
  
  const regex = new RegExp(`^${regexPath}$`)
  const match = path.match(regex)
  
  if (match) {
    const params = {}
    paramNames.forEach((name, i) => {
      params[name] = match[i + 1]
    })
    
    return { path, params }
  }
  
  return null
}

嵌套路由匹配

javascript
function matchNestedRoutes(path, routes) {
  const segments = path.split('/').filter(Boolean)
  let currentRoutes = routes
  const matchedRoutes = []
  
  for (const segment of segments) {
    let matched = null
    
    for (const route of currentRoutes) {
      const result = matchPath(segment, route.path)
      if (result) {
        matched = { route, params: result.params }
        break
      }
    }
    
    if (!matched) {
      return null
    }
    
    matchedRoutes.push(matched)
    currentRoutes = matched.route.children || []
  }
  
  return matchedRoutes
}

历史管理

Hash 模式

javascript
class HashHistory {
  constructor() {
    window.addEventListener('hashchange', this.handleHashChange.bind(this))
  }
  
  push(path) {
    window.location.hash = path
  }
  
  replace(path) {
    const url = new URL(window.location)
    url.hash = path
    window.history.replaceState(null, '', url)
  }
  
  go(n) {
    window.history.go(n)
  }
  
  handleHashChange() {
    // 处理 hash 变化
  }
}

History 模式

javascript
class HTML5History {
  constructor() {
    window.addEventListener('popstate', this.handlePopState.bind(this))
  }
  
  push(path) {
    window.history.pushState(null, '', path)
  }
  
  replace(path) {
    window.history.replaceState(null, '', path)
  }
  
  go(n) {
    window.history.go(n)
  }
  
  handlePopState() {
    // 处理 popstate 事件
  }
}

性能优化

1. 路由懒加载

javascript
const routes = [
  {
    path: '/user',
    component: () => import('./views/User.vue')
  }
]

2. 路由预加载

javascript
router.beforeEach((to, from, next) => {
  if (to.matched.length) {
    to.matched.forEach(record => {
      if (typeof record.component === 'function') {
        record.component()
      }
    })
  }
  next()
})

3. 路由缓存

javascript
const cachedComponents = new Map()

function loadComponent(loader) {
  if (cachedComponents.has(loader)) {
    return Promise.resolve(cachedComponents.get(loader))
  }
  
  return loader().then(component => {
    cachedComponents.set(loader, component)
    return component
  })
}

总结

Vue Router 的架构体现了以下特点:

  1. 声明式:使用声明式路由配置
  2. 组件化:路由与组件绑定
  3. 灵活性:支持多种路由模式
  4. 可扩展:支持自定义路由

理解 Vue Router 的架构有助于更好地使用和优化 Vue Router。

参考资源

架构师AI杜公众号二维码

扫描二维码关注"架构师AI杜"公众号,获取更多技术内容和最新动态