Skip to content

RouteRecordNormalized 接口 | Vue Router API

概述

RouteRecordNormalized 接口表示标准化后的路由记录信息。它包含了路由配置的完整详细信息,用于描述路由匹配和组件渲染。

接口定义

typescript
interface RouteRecordNormalized {
  // 路径信息
  readonly path: string
  readonly regex: RegExp
  
  // 组件信息
  readonly components: Record<string, Component> | null | undefined
  readonly instances: Record<string, ComponentPublicInstance> | null | undefined
  readonly enteredCbs: Record<string, NavigationGuard[]> | undefined
  
  // 路由配置
  readonly name: string | symbol | undefined | null
  readonly meta: Record<string, any>
  readonly props: Record<string, _RouteRecordProps>
  readonly beforeEnter?: NavigationGuardWithThis<undefined>
  readonly leaveGuards: Set<NavigationGuard>
  readonly updateGuards: Set<NavigationGuard>
  
  // 父子关系
  readonly parent: RouteRecordNormalized | undefined
  readonly children: RouteRecordNormalized[]
  readonly aliasOf: RouteRecordNormalized | undefined
}

核心属性详解

path - 路由路径

类型: string说明: 路由的路径模式

javascript
routeRecord.path // '/user/:id'

regex - 正则表达式

类型: RegExp说明: 用于路径匹配的正则表达式

javascript
// 对于路径 '/user/:id'
routeRecord.regex // 匹配用户ID的正则表达式

components - 路由组件

类型: Record<string, Component> | null | undefined说明: 路由对应的组件映射

javascript
// 单组件路由
routeRecord.components // { default: UserComponent }

// 多组件路由(命名视图)
routeRecord.components // { 
//   default: MainContent, 
//   sidebar: SidebarComponent 
// }

instances - 组件实例

类型: Record<string, ComponentPublicInstance> | null | undefined说明: 当前路由组件的实例

javascript
// 访问组件实例
const mainInstance = routeRecord.instances?.default

name - 路由名称

类型: string | symbol | undefined | null说明: 路由的唯一名称

javascript
routeRecord.name // 'user-profile'

meta - 路由元信息

类型: Record<string, any>说明: 路由的元数据信息

javascript
routeRecord.meta // { requiresAuth: true, title: '用户资料' }

props - 属性传递配置

类型: Record<string, _RouteRecordProps>说明: 路由参数传递给组件的配置

javascript
routeRecord.props // { default: true }  // 将params作为props传递

parent - 父路由记录

类型: RouteRecordNormalized | undefined说明: 父级路由记录(用于嵌套路由)

javascript
if (routeRecord.parent) {
  console.log('父路由:', routeRecord.parent.path)
}

children - 子路由记录

类型: RouteRecordNormalized[]说明: 子级路由记录数组

javascript
routeRecord.children.forEach(child => {
  console.log('子路由:', child.path)
})

实际应用场景

场景 1:路由信息分析和调试

javascript
// 路由调试工具
class RouteDebugger {
  static logRouteInfo(route) {
    console.log('=== 路由信息分析 ===')
    
    route.matched.forEach((record, index) => {
      console.log(`\n--- 路由记录 ${index + 1} ---`)
      console.log('路径:', record.path)
      console.log('名称:', record.name)
      console.log('正则:', record.regex)
      console.log('元信息:', record.meta)
      console.log('组件:', Object.keys(record.components || {}))
      
      if (record.parent) {
        console.log('父路由:', record.parent.path)
      }
      
      if (record.children.length > 0) {
        console.log('子路由数量:', record.children.length)
      }
    })
  }
  
  // 查找特定路由记录
  static findRouteRecord(route, predicate) {
    return route.matched.find(record => predicate(record))
  }
  
  // 获取路由深度
  static getRouteDepth(route) {
    return route.matched.length
  }
}

场景 2:动态权限检查

javascript
// 基于路由记录的权限验证
function checkRoutePermissions(route, userPermissions) {
  const routeRecord = route.matched[route.matched.length - 1]
  
  if (!routeRecord) {
    return { allowed: false, reason: '路由不存在' }
  }
  
  // 检查路由元信息中的权限要求
  const requiredPermissions = routeRecord.meta?.permissions || []
  
  if (requiredPermissions.length === 0) {
    return { allowed: true }
  }
  
  // 验证用户权限
  const hasAllPermissions = requiredPermissions.every(perm => 
    userPermissions.includes(perm)
  )
  
  return {
    allowed: hasAllPermissions,
    reason: hasAllPermissions ? '' : '权限不足',
    missingPermissions: requiredPermissions.filter(perm => 
      !userPermissions.includes(perm)
    )
  }
}

// 使用示例
const permissionCheck = checkRoutePermissions(
  currentRoute, 
  user.permissions
)

if (!permissionCheck.allowed) {
  showPermissionError(permissionCheck.missingPermissions)
}

场景 3:面包屑导航生成

javascript
// 基于路由记录生成面包屑
function generateBreadcrumbs(route) {
  return route.matched
    .filter(record => record.meta?.breadcrumb !== undefined)
    .map((record, index) => {
      const isLast = index === route.matched.length - 1
      
      return {
        title: record.meta.breadcrumb,
        path: buildBreadcrumbPath(route, record, index),
        active: isLast,
        record: record
      }
    })
}

// 构建面包屑路径
function buildBreadcrumbPath(route, record, index) {
  // 对于嵌套路由,需要构建完整路径
  if (index === 0) {
    return record.path
  }
  
  // 获取当前路由参数,构建实际路径
  const params = { ...route.params }
  let path = record.path
  
  // 替换路径中的参数
  Object.keys(params).forEach(key => {
    if (path.includes(`:${key}`)) {
      path = path.replace(`:${key}`, params[key])
    }
  })
  
  return path
}

高级用法

路由记录分析工具

javascript
// 路由记录分析器
class RouteRecordAnalyzer {
  constructor(router) {
    this.router = router
  }
  
  // 获取所有路由记录
  getAllRouteRecords() {
    return this.router.getRoutes()
  }
  
  // 按条件筛选路由记录
  findRouteRecords(predicate) {
    return this.getAllRouteRecords().filter(predicate)
  }
  
  // 查找包含特定元信息的路由
  findRoutesWithMeta(key, value) {
    return this.findRouteRecords(record => 
      record.meta && record.meta[key] === value
    )
  }
  
  // 获取路由树结构
  getRouteTree() {
    const routes = this.getAllRouteRecords()
    const rootRoutes = routes.filter(route => !route.parent)
    
    return rootRoutes.map(route => this.buildRouteTree(route, routes))
  }
  
  buildRouteTree(route, allRoutes) {
    const children = allRoutes.filter(r => r.parent === route)
    
    return {
      path: route.path,
      name: route.name,
      meta: route.meta,
      children: children.map(child => this.buildRouteTree(child, allRoutes))
    }
  }
  
  // 路由使用统计
  analyzeRouteUsage() {
    const routes = this.getAllRouteRecords()
    const stats = {}
    
    routes.forEach(route => {
      stats[route.path] = {
        name: route.name,
        componentCount: Object.keys(route.components || {}).length,
        hasChildren: route.children.length > 0,
        metaKeys: Object.keys(route.meta || {}),
        depth: this.getRouteDepth(route)
      }
    })
    
    return stats
  }
  
  getRouteDepth(route) {
    let depth = 0
    let current = route
    
    while (current.parent) {
      depth++
      current = current.parent
    }
    
    return depth
  }
}

动态路由管理

javascript
// 动态路由管理器
class DynamicRouteManager {
  constructor(router) {
    this.router = router
    this.addedRoutes = new Map()
  }
  
  // 动态添加功能路由
  addFeatureRoutes(featureName, routes) {
    const removeFunctions = []
    
    routes.forEach(route => {
      // 添加特征标记
      const enhancedRoute = {
        ...route,
        meta: {
          ...route.meta,
          dynamic: true,
          feature: featureName
        }
      }
      
      const removeFn = this.router.addRoute(enhancedRoute)
      removeFunctions.push(removeFn)
      
      // 记录添加的路由
      this.addedRoutes.set(route.name || route.path, {
        route: enhancedRoute,
        remove: removeFn
      })
    })
    
    return () => {
      removeFunctions.forEach(fn => fn())
      routes.forEach(route => {
        this.addedRoutes.delete(route.name || route.path)
      })
    }
  }
  
  // 根据条件禁用路由
  disableRoutes(predicate) {
    const routesToDisable = this.findRouteRecords(predicate)
    
    routesToDisable.forEach(route => {
      if (this.addedRoutes.has(route.name || route.path)) {
        const routeInfo = this.addedRoutes.get(route.name || route.path)
        routeInfo.remove()
        this.addedRoutes.delete(route.name || route.path)
      }
    })
  }
  
  // 重新启用路由
  enableRoutes(predicate) {
    // 实现重新启用逻辑
  }
  
  findRouteRecords(predicate) {
    return Array.from(this.addedRoutes.values())
      .map(info => info.route)
      .filter(predicate)
  }
}

最佳实践

1. 路由记录验证

javascript
// 路由记录验证工具
function validateRouteRecord(record) {
  const errors = []
  
  if (!record.path) {
    errors.push('路由路径不能为空')
  }
  
  if (!record.path.startsWith('/')) {
    errors.push('路由路径必须以 / 开头')
  }
  
  if (!record.components || Object.keys(record.components).length === 0) {
    errors.push('路由必须指定至少一个组件')
  }
  
  // 验证路径参数
  const paramMatches = record.path.match(/:\w+/g) || []
  paramMatches.forEach(param => {
    const paramName = param.slice(1)
    if (!/^[a-zA-Z_]\w*$/.test(paramName)) {
      errors.push(`无效的参数名: ${paramName}`)
    }
  })
  
  return {
    valid: errors.length === 0,
    errors
  }
}

2. 路由信息缓存

javascript
// 路由信息缓存
class RouteInfoCache {
  constructor() {
    this.cache = new Map()
    this.stats = {
      hits: 0,
      misses: 0,
      size: 0
    }
  }
  
  getRouteInfo(route) {
    const key = this.generateCacheKey(route)
    
    if (this.cache.has(key)) {
      this.stats.hits++
      return this.cache.get(key)
    }
    
    this.stats.misses++
    const info = this.analyzeRoute(route)
    this.cache.set(key, info)
    this.stats.size = this.cache.size
    
    return info
  }
  
  generateCacheKey(route) {
    return route.fullPath
  }
  
  analyzeRoute(route) {
    return {
      depth: route.matched.length,
      components: route.matched.flatMap(record => 
        Object.keys(record.components || {})
      ),
      meta: this.mergeRouteMeta(route),
      params: route.params,
      query: route.query
    }
  }
  
  mergeRouteMeta(route) {
    return route.matched.reduce((meta, record) => ({
      ...meta,
      ...record.meta
    }), {})
  }
  
  clear() {
    this.cache.clear()
    this.stats = { hits: 0, misses: 0, size: 0 }
  }
}

注意事项

  1. 性能考虑 - 避免频繁访问路由记录信息
  2. 内存管理 - 注意路由记录缓存的大小
  3. 类型安全 - 使用 TypeScript 增强类型检查
  4. 兼容性 - 确保路由记录操作与 Vue Router 版本兼容

🎯 总结:RouteRecordNormalized 提供了深入的路由配置信息访问能力,是构建高级路由功能的基础。

🚀 Vue Router - 让前端路由变得简单而强大 | 构建现代化单页应用的最佳选择