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?.defaultname - 路由名称
类型: 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 }
}
}注意事项
- 性能考虑 - 避免频繁访问路由记录信息
- 内存管理 - 注意路由记录缓存的大小
- 类型安全 - 使用 TypeScript 增强类型检查
- 兼容性 - 确保路由记录操作与 Vue Router 版本兼容
🎯 总结:RouteRecordNormalized 提供了深入的路由配置信息访问能力,是构建高级路由功能的基础。