Skip to content

routeLocationKey Variable | Vue Router

routeLocationKey is a symbol used as an injection key for providing and injecting the current route location in Vue components. It enables type-safe access to route information throughout your application. 🗺️

📋 Variable Definition

typescript
const routeLocationKey: InjectionKey<RouteLocationNormalizedLoaded> = Symbol()

🎯 Purpose and Usage

The routeLocationKey variable provides a standardized way to inject the current route location into Vue components using Vue's dependency injection system. It gives you access to comprehensive route information with full type safety.

Key Benefits:

  • Type Safety - Full TypeScript support for route data
  • Reactive Access - Get reactive route information
  • Dependency Injection - Clean component architecture
  • Comprehensive Data - Access to all route properties

🔍 Technical Details

Injection Key Type

routeLocationKey is defined as an InjectionKey<RouteLocationNormalizedLoaded>, providing type information for the current route location.

Normalized Route Data

The injected value is a RouteLocationNormalizedLoaded object, which contains:

  • Complete route information after normalization
  • Reactive properties that update with route changes
  • All route parameters, query, hash, and meta data

💡 Practical Usage Examples

Basic Route Location Injection

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

// Inject current route location
const route = inject(routeLocationKey)

// Access route properties reactively
const currentPath = computed(() => route?.path)
const queryParams = computed(() => route?.query)
const routeParams = computed(() => route?.params)
</script>

<template>
  <div>
    <p>Current path: {{ currentPath }}</p>
    <p>Query parameters: {{ queryParams }}</p>
    <p>Route parameters: {{ routeParams }}</p>
  </div>
</template>

Route-Aware Component

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

interface Props {
  activePaths?: string[]
}

const props = defineProps<Props>()
const route = inject(routeLocationKey)

// Check if current route matches active paths
const isActive = computed(() => {
  if (!route || !props.activePaths) return false
  return props.activePaths.some(path => route.path.startsWith(path))
})

// Get specific parameter with type safety
const userId = computed(() => {
  return route?.params.id as string | undefined
})

// Watch for route changes
watch(() => route?.path, (newPath, oldPath) => {
  console.log('Route changed:', oldPath, '→', newPath)
})
</script>

<template>
  <div :class="{ active: isActive }">
    <slot :route="route" :isActive="isActive" />
  </div>
</template>

Route-Based Service

typescript
import { inject } from 'vue'
import { routeLocationKey } from 'vue-router'
import type { RouteLocationNormalizedLoaded } from 'vue-router'

class RouteAnalyticsService {
  private route: RouteLocationNormalizedLoaded | undefined
  
  constructor() {
    this.route = inject(routeLocationKey, undefined)
  }
  
  // Track page views based on route changes
  trackPageView() {
    if (!this.route) return
    
    analytics.track('page_view', {
      path: this.route.path,
      query: this.route.query,
      params: this.route.params,
      timestamp: Date.now()
    })
  }
  
  // Get route-specific configuration
  getRouteConfig() {
    if (!this.route) return null
    
    return {
      requiresAuth: this.route.meta.requiresAuth === true,
      pageTitle: this.route.meta.title as string || 'Default Title',
      breadcrumbs: this.route.meta.breadcrumbs as string[] || []
    }
  }
  
  // Check if current route matches pattern
  isRouteMatching(pattern: string | RegExp): boolean {
    if (!this.route) return false
    
    if (typeof pattern === 'string') {
      return this.route.path === pattern
    } else {
      return pattern.test(this.route.path)
    }
  }
}

🔧 Advanced Patterns

Type-Safe Route Injection Utility

typescript
import { inject } from 'vue'
import { routeLocationKey } from 'vue-router'
import type { RouteLocationNormalizedLoaded } from 'vue-router'

class RouteInjection {
  // Safe route injection with validation
  static injectRoute(): RouteLocationNormalizedLoaded {
    const route = inject(routeLocationKey)
    
    if (!route) {
      throw new Error(
        'Route location not found. ' +
        'Make sure the component is within a router context.'
      )
    }
    
    return route
  }
  
  // Optional route injection
  static injectOptionalRoute(): RouteLocationNormalizedLoaded | undefined {
    return inject(routeLocationKey, undefined)
  }
  
  // Route injection with custom fallback
  static injectRouteWithFallback(fallback: Partial<RouteLocationNormalizedLoaded>) {
    const route = inject(routeLocationKey, undefined)
    return route ? route : { ...fallback } as RouteLocationNormalizedLoaded
  }
}

// Usage examples
const route = RouteInjection.injectRoute() // Throws if not available
const optionalRoute = RouteInjection.injectOptionalRoute() // Undefined if not available

Route-Based Composition Function

typescript
import { inject, computed, watch } from 'vue'
import { routeLocationKey } from 'vue-router'
import type { RouteLocationNormalizedLoaded } from 'vue-router'

export function useRouteInfo() {
  const route = inject(routeLocationKey)
  
  if (!route) {
    throw new Error('useRouteInfo must be used within a router context')
  }
  
  // Computed properties for common route data
  const currentPath = computed(() => route.path)
  const queryParams = computed(() => route.query)
  const routeParams = computed(() => route.params)
  const routeMeta = computed(() => route.meta)
  const routeHash = computed(() => route.hash)
  
  // Route matching utilities
  const isRouteActive = (path: string) => route.path === path
  const isRouteStartingWith = (prefix: string) => route.path.startsWith(prefix)
  const hasQueryParam = (key: string) => key in route.query
  const hasRouteParam = (key: string) => key in route.params
  
  // Watch for specific route changes
  const watchRouteParam = (paramKey: string, callback: (value: string) => void) => {
    watch(() => route.params[paramKey], (newValue, oldValue) => {
      if (newValue !== oldValue) {
        callback(newValue as string)
      }
    })
  }
  
  const watchQueryParam = (queryKey: string, callback: (value: string) => void) => {
    watch(() => route.query[queryKey], (newValue, oldValue) => {
      if (newValue !== oldValue) {
        callback(newValue as string)
      }
    })
  }
  
  return {
    route, // Full route object
    currentPath,
    queryParams,
    routeParams,
    routeMeta,
    routeHash,
    isRouteActive,
    isRouteStartingWith,
    hasQueryParam,
    hasRouteParam,
    watchRouteParam,
    watchQueryParam
  }
}

// Usage in component
const { 
  currentPath, 
  queryParams, 
  watchRouteParam 
} = useRouteInfo()

watchRouteParam('id', (userId) => {
  loadUserData(userId)
})

Route-Based Permission System

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

class RoutePermissionChecker {
  private route: RouteLocationNormalizedLoaded | undefined
  
  constructor() {
    this.route = inject(routeLocationKey, undefined)
  }
  
  // Check if user can access current route
  canAccess(currentUser: User): boolean {
    if (!this.route) return true // Default to allowed if no route
    
    // Check authentication requirement
    if (this.route.meta.requiresAuth && !currentUser.isAuthenticated) {
      return false
    }
    
    // Check role-based permissions
    const requiredRoles = this.route.meta.requiredRoles as string[] | undefined
    if (requiredRoles && requiredRoles.length > 0) {
      const hasRequiredRole = requiredRoles.some(role =>
        currentUser.roles.includes(role)
      )
      if (!hasRequiredRole) return false
    }
    
    // Check feature flags
    const requiredFeatures = this.route.meta.requiredFeatures as string[] | undefined
    if (requiredFeatures && requiredFeatures.length > 0) {
      const hasFeatures = requiredFeatures.every(feature =>
        currentUser.features.includes(feature)
      )
      if (!hasFeatures) return false
    }
    
    return true
  }
  
  // Get permission requirements for current route
  getPermissionRequirements(): PermissionRequirements {
    if (!this.route) return { requiresAuth: false }
    
    return {
      requiresAuth: this.route.meta.requiresAuth === true,
      requiredRoles: this.route.meta.requiredRoles as string[] || [],
      requiredFeatures: this.route.meta.requiredFeatures as string[] || []
    }
  }
}

🚨 Important Considerations

Injection Context Requirements

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

const route = inject(routeLocationKey) // Works in setup context
</script>

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

Reactivity and Performance

typescript
// The injected route is reactive
const route = inject(routeLocationKey)

// ✅ Good: Use computed properties for derived values
const userId = computed(() => route?.params.id as string)

// ❌ Avoid: Directly using route properties in templates
// This can cause unnecessary re-renders
<template>
  <div>{{ route?.params.id }}</div> <!-- Potentially inefficient -->
</template>

// ✅ Better: Use computed properties
<template>
  <div>{{ userId }}</div>
</template>

📚 Best Practices

Safe Route Access Pattern

typescript
class SafeRouteAccess {
  // Always validate route availability
  static ensureRoute(route: RouteLocationNormalizedLoaded | undefined): RouteLocationNormalizedLoaded {
    if (!route) {
      throw new Error(
        'Route location is not available. ' +
        'Make sure your component is properly initialized.'
      )
    }
    return route
  }
  
  // Safe parameter access with type checking
  static getRouteParam(route: RouteLocationNormalizedLoaded | undefined, param: string): string | undefined {
    const actualRoute = this.ensureRoute(route)
    return actualRoute.params[param] as string | undefined
  }
  
  // Safe query parameter access
  static getQueryParam(route: RouteLocationNormalizedLoaded | undefined, param: string): string | undefined {
    const actualRoute = this.ensureRoute(route)
    const value = actualRoute.query[param]
    return Array.isArray(value) ? value[0] : value
  }
}

Route Injection Utility

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

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

💡 Pro Tip: Use routeLocationKey for advanced route injection scenarios. For most components, prefer using useRoute() from Vue Router's composition API as it's simpler and more straightforward.

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