Skip to content

matchedRouteKey Variable | Vue Router

matchedRouteKey is a symbol used as an injection key for providing and injecting the currently matched route record in Vue components. It gives you access to the route configuration that matches the current URL. 🎯

📋 Variable Definition

typescript
const matchedRouteKey: InjectionKey<RouteRecordNormalized> = Symbol()

🎯 Purpose and Usage

The matchedRouteKey variable provides a standardized way to inject the matched route record into Vue components using Vue's dependency injection system. This gives you access to the route configuration that was used to match the current URL.

Key Benefits:

  • Route Configuration Access - Get the route record that matched
  • Meta Information - Access route meta data and configuration
  • Component Information - See which components are associated
  • Type Safety - Full TypeScript support for route records

🔍 Technical Details

Injection Key Type

matchedRouteKey is defined as an InjectionKey<RouteRecordNormalized>, providing type information for the matched route record.

Route Record Information

The injected value is a RouteRecordNormalized object, which contains:

  • Complete route configuration
  • Component mappings
  • Route meta information
  • Children routes and aliases

💡 Practical Usage Examples

Basic Matched Route Injection

vue
<script setup>
import { inject } from 'vue'
import { matchedRouteKey } from 'vue-router'

// Inject matched route record
const matchedRoute = inject(matchedRouteKey)

// Access route configuration
const routeName = computed(() => matchedRoute?.name)
const routePath = computed(() => matchedRoute?.path)
const routeMeta = computed(() => matchedRoute?.meta)
const routeComponents = computed(() => matchedRoute?.components)
</script>

<template>
  <div v-if="matchedRoute">
    <h3>Matched Route Information</h3>
    <p>Name: {{ routeName }}</p>
    <p>Path: {{ routePath }}</p>
    <p>Meta: {{ routeMeta }}</p>
  </div>
</template>

Route Configuration Component

vue
<script setup>
import { inject, computed } from 'vue'
import { matchedRouteKey } from 'vue-router'

interface Props {
  showDetails?: boolean
}

const props = defineProps<Props>()
const matchedRoute = inject(matchedRouteKey)

// Extract useful information from matched route
const routeInfo = computed(() => {
  if (!matchedRoute) return null
  
  return {
    name: matchedRoute.name,
    path: matchedRoute.path,
    hasChildren: matchedRoute.children.length > 0,
    childCount: matchedRoute.children.length,
    hasAliases: matchedRoute.alias.length > 0,
    metaKeys: Object.keys(matchedRoute.meta),
    componentNames: Object.keys(matchedRoute.components)
  }
})

// Check if route has specific meta property
const hasMetaProperty = (key: string) => {
  return matchedRoute ? key in matchedRoute.meta : false
}

// Get specific meta value with type safety
const getMetaValue = <T>(key: string, defaultValue: T): T => {
  if (!matchedRoute || !(key in matchedRoute.meta)) {
    return defaultValue
  }
  return matchedRoute.meta[key] as T
}
</script>

<template>
  <div v-if="routeInfo && props.showDetails" class="route-info">
    <h4>Route Configuration</h4>
    <ul>
      <li>Name: {{ routeInfo.name }}</li>
      <li>Path: {{ routeInfo.path }}</li>
      <li>Children: {{ routeInfo.childCount }}</li>
      <li>Components: {{ routeInfo.componentNames.join(', ') }}</li>
    </ul>
  </div>
</template>

Route-Based Feature Detection

typescript
import { inject } from 'vue'
import { matchedRouteKey } from 'vue-router'
import type { RouteRecordNormalized } from 'vue-router'

class RouteFeatureDetector {
  private matchedRoute: RouteRecordNormalized | undefined
  
  constructor() {
    this.matchedRoute = inject(matchedRouteKey, undefined)
  }
  
  // Check if current route has specific feature
  hasFeature(feature: string): boolean {
    if (!this.matchedRoute) return false
    
    const features = this.matchedRoute.meta.features as string[] | undefined
    return features ? features.includes(feature) : false
  }
  
  // Get all features for current route
  getFeatures(): string[] {
    if (!this.matchedRoute) return []
    
    const features = this.matchedRoute.meta.features as string[] | undefined
    return features || []
  }
  
  // Check if route requires specific permission
  requiresPermission(permission: string): boolean {
    if (!this.matchedRoute) return false
    
    const permissions = this.matchedRoute.meta.permissions as string[] | undefined
    return permissions ? permissions.includes(permission) : false
  }
  
  // Get route-specific configuration
  getRouteConfig(): RouteConfig {
    if (!this.matchedRoute) return {}
    
    return {
      layout: this.matchedRoute.meta.layout as string || 'default',
      requiresAuth: this.matchedRoute.meta.requiresAuth === true,
      pageTitle: this.matchedRoute.meta.title as string || '',
      breadcrumbs: this.matchedRoute.meta.breadcrumbs as string[] || []
    }
  }
}

🔧 Advanced Patterns

Type-Safe Matched Route Injection

typescript
import { inject } from 'vue'
import { matchedRouteKey } from 'vue-router'
import type { RouteRecordNormalized } from 'vue-router'

class MatchedRouteInjection {
  // Safe injection with validation
  static injectMatchedRoute(): RouteRecordNormalized {
    const matchedRoute = inject(matchedRouteKey)
    
    if (!matchedRoute) {
      throw new Error(
        'Matched route not found. ' +
        'Make sure the component is within a router context.'
      )
    }
    
    return matchedRoute
  }
  
  // Optional injection
  static injectOptionalMatchedRoute(): RouteRecordNormalized | undefined {
    return inject(matchedRouteKey, undefined)
  }
  
  // Injection with fallback configuration
  static injectMatchedRouteWithFallback(fallback: Partial<RouteRecordNormalized>) {
    const matchedRoute = inject(matchedRouteKey, undefined)
    return matchedRoute ? matchedRoute : { ...fallback } as RouteRecordNormalized
  }
}

// Usage examples
const matchedRoute = MatchedRouteInjection.injectMatchedRoute()
const optionalRoute = MatchedRouteInjection.injectOptionalMatchedRoute()

Matched Route Composition Function

typescript
import { inject, computed } from 'vue'
import { matchedRouteKey } from 'vue-router'
import type { RouteRecordNormalized } from 'vue-router'

export function useMatchedRoute() {
  const matchedRoute = inject(matchedRouteKey)
  
  if (!matchedRoute) {
    throw new Error('useMatchedRoute must be used within a router context')
  }
  
  // Computed properties for common route record data
  const routeName = computed(() => matchedRoute.name)
  const routePath = computed(() => matchedRoute.path)
  const routeMeta = computed(() => matchedRoute.meta)
  const routeComponents = computed(() => matchedRoute.components)
  const routeChildren = computed(() => matchedRoute.children)
  const routeAliases = computed(() => matchedRoute.alias)
  
  // Route record analysis
  const routeAnalysis = computed(() => ({
    hasChildren: matchedRoute.children.length > 0,
    childCount: matchedRoute.children.length,
    hasAliases: matchedRoute.alias.length > 0,
    aliasCount: matchedRoute.alias.length,
    componentCount: Object.keys(matchedRoute.components).length,
    metaKeyCount: Object.keys(matchedRoute.meta).length
  }))
  
  // Meta data utilities
  const getMetaValue = <T>(key: string, defaultValue: T): T => {
    return (matchedRoute.meta[key] as T) || defaultValue
  }
  
  const hasMetaKey = (key: string): boolean => {
    return key in matchedRoute.meta
  }
  
  // Component utilities
  const getComponent = (name: string = 'default') => {
    return matchedRoute.components[name]
  }
  
  const hasComponent = (name: string = 'default'): boolean => {
    return name in matchedRoute.components
  }
  
  return {
    matchedRoute, // Full matched route object
    routeName,
    routePath,
    routeMeta,
    routeComponents,
    routeChildren,
    routeAliases,
    routeAnalysis,
    getMetaValue,
    hasMetaKey,
    getComponent,
    hasComponent
  }
}

// Usage in component
const { 
  routeMeta, 
  getMetaValue, 
  routeAnalysis 
} = useMatchedRoute()

const pageTitle = getMetaValue('title', 'Default Title')
const requiresAuth = getMetaValue('requiresAuth', false)

Dynamic Layout System Based on Matched Route

typescript
import { inject } from 'vue'
import { matchedRouteKey } from 'vue-router'

class DynamicLayoutSystem {
  private matchedRoute: RouteRecordNormalized | undefined
  
  constructor() {
    this.matchedRoute = inject(matchedRouteKey, undefined)
  }
  
  // Get layout component based on route meta
  getLayoutComponent(): Component {
    if (!this.matchedRoute) {
      return DefaultLayout
    }
    
    const layoutName = this.matchedRoute.meta.layout as string || 'default'
    
    switch (layoutName) {
      case 'admin':
        return AdminLayout
      case 'auth':
        return AuthLayout
      case 'empty':
        return EmptyLayout
      default:
        return DefaultLayout
    }
  }
  
  // Check if route should use specific layout
  shouldUseLayout(layout: string): boolean {
    if (!this.matchedRoute) return layout === 'default'
    
    const routeLayout = this.matchedRoute.meta.layout as string || 'default'
    return routeLayout === layout
  }
  
  // Get layout configuration
  getLayoutConfig(): LayoutConfig {
    if (!this.matchedRoute) return {}
    
    return {
      showHeader: this.matchedRoute.meta.showHeader !== false,
      showFooter: this.matchedRoute.meta.showFooter !== false,
      showSidebar: this.matchedRoute.meta.showSidebar === true,
      sidebarCollapsed: this.matchedRoute.meta.sidebarCollapsed === true
    }
  }
}

🚨 Important Considerations

Injection Context Requirements

typescript
// ✅ Correct: Using within component setup
<script setup>
import { inject } from 'vue'
import { matchedRouteKey } from 'vue-router'

const matchedRoute = inject(matchedRouteKey) // Works in setup context
</script>

// ❌ Incorrect: Using outside component context
// This will not work - no injection context available
const matchedRoute = inject(matchedRouteKey) // undefined or error

Matched Route vs Current Route

typescript
// Important distinction:
// - matchedRouteKey: Provides the route record that matched the URL
// - routeLocationKey: Provides the current route location information

// They contain different but complementary information:
// matchedRoute: Configuration (meta, components, path pattern)
// routeLocation: Current state (params, query, actual path)

📚 Best Practices

Safe Matched Route Access

typescript
class SafeMatchedRouteAccess {
  // Always validate matched route availability
  static ensureMatchedRoute(matchedRoute: RouteRecordNormalized | undefined): RouteRecordNormalized {
    if (!matchedRoute) {
      throw new Error(
        'Matched route is not available. ' +
        'Make sure your component is properly initialized.'
      )
    }
    return matchedRoute
  }
  
  // Safe meta data access
  static getMetaValue<T>(
    matchedRoute: RouteRecordNormalized | undefined, 
    key: string, 
    defaultValue: T
  ): T {
    const actualRoute = this.ensureMatchedRoute(matchedRoute)
    return (actualRoute.meta[key] as T) || defaultValue
  }
}

Matched Route Injection Utility

typescript
// Create a reusable matched route injection utility
export function createMatchedRouteInjection<T extends Record<string, any>>(
  customInjections?: T
) {
  const matchedRoute = inject(matchedRouteKey)
  
  if (!matchedRoute) {
    throw new Error('Matched route injection failed')
  }
  
  return {
    matchedRoute,
    ...customInjections
  }
}

// Usage: Extend with custom functionality
const { matchedRoute, customFeature } = createMatchedRouteInjection({
  customFeature: () => { /* custom logic */ }
})

💡 Pro Tip: Use matchedRouteKey when you need access to the route configuration that matched the current URL. This is particularly useful for dynamic layout systems, permission checks, and feature flags based on route configuration.

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