Skip to content

routerKey Variable | Vue Router

routerKey is a symbol used as an injection key for providing and injecting the router instance in Vue components. It enables type-safe access to the router instance throughout your application. 🔑

📋 Variable Definition

typescript
const routerKey: InjectionKey<Router> = Symbol()

🎯 Purpose and Usage

The routerKey variable provides a standardized way to inject the router instance into Vue components using Vue's dependency injection system. It ensures type safety and prevents naming conflicts.

Key Benefits:

  • Type Safety - Ensures proper typing for injected router
  • Dependency Injection - Enables clean component architecture
  • Framework Integration - Works seamlessly with Vue's injection system
  • Avoids Magic Strings - Uses symbols instead of string keys

🔍 Technical Details

Injection Key Type

routerKey is defined as an InjectionKey<Router>, which is a Vue-specific type that provides type information for dependency injection.

Symbol-Based Identification

As a symbol, routerKey is guaranteed to be unique, preventing conflicts with other injection keys in your application.

💡 Practical Usage Examples

Basic Router Injection

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

// Inject router instance using the key
const router = inject(routerKey)

// Use the router instance
function navigateToHome() {
  router?.push('/')
}
</script>

Custom Component with Router Access

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

interface Props {
  to: string | RouteLocationRaw
}

const props = defineProps<Props>()
const router = inject(routerKey)

const navigate = () => {
  if (!router) {
    console.warn('Router not available')
    return
  }
  
  if (typeof props.to === 'string') {
    router.push(props.to)
  } else {
    router.push(props.to)
  }
}
</script>

<template>
  <button @click="navigate">
    <slot>Navigate</slot>
  </button>
</template>

Router-Aware Service

typescript
import { inject } from 'vue'
import { routerKey } from 'vue-router'
import type { Router } from 'vue-router'

class NavigationService {
  private router: Router | undefined
  
  constructor() {
    // Inject router in constructor or initialize later
    this.router = inject(routerKey, undefined)
  }
  
  initialize(router: Router) {
    this.router = router
  }
  
  navigateTo(path: string, query?: Record<string, string>) {
    if (!this.router) {
      throw new Error('Router not initialized')
    }
    
    this.router.push({
      path,
      query
    })
  }
  
  // Static method for quick navigation
  static navigate(path: string) {
    const router = inject(routerKey)
    router?.push(path)
  }
}

// Usage in component
const navigationService = new NavigationService()
</script>

🔧 Advanced Patterns

Type-Safe Router Injection Utility

typescript
import { inject, type InjectionKey } from 'vue'
import { routerKey } from 'vue-router'
import type { Router } from 'vue-router'

class RouterInjection {
  // Safe router injection with fallback
  static injectRouter(): Router {
    const router = inject(routerKey)
    
    if (!router) {
      throw new Error(
        'Router instance not found. ' +
        'Make sure the component is wrapped in a router provider.'
      )
    }
    
    return router
  }
  
  // Optional router injection
  static injectOptionalRouter(): Router | undefined {
    return inject(routerKey, undefined)
  }
  
  // Router injection with custom error message
  static injectRouterWithMessage(errorMessage: string): Router {
    const router = inject(routerKey)
    
    if (!router) {
      throw new Error(errorMessage)
    }
    
    return router
  }
}

// Usage examples
const router = RouterInjection.injectRouter() // Throws if not available
const optionalRouter = RouterInjection.injectOptionalRouter() // Undefined if not available

Router-Aware Composition Function

typescript
import { inject } from 'vue'
import { routerKey } from 'vue-router'
import type { Router } from 'vue-router'

export function useRouterNavigation() {
  const router = inject(routerKey)
  
  if (!router) {
    throw new Error('useRouterNavigation must be used within a router context')
  }
  
  const navigate = (to: string | RouteLocationRaw) => {
    if (typeof to === 'string') {
      router.push(to)
    } else {
      router.push(to)
    }
  }
  
  const replace = (to: string | RouteLocationRaw) => {
    if (typeof to === 'string') {
      router.replace(to)
    } else {
      router.replace(to)
    }
  }
  
  const go = (delta: number) => {
    router.go(delta)
  }
  
  const back = () => {
    router.back()
  }
  
  const forward = () => {
    router.forward()
  }
  
  return {
    navigate,
    replace,
    go,
    back,
    forward,
    router // Expose the full router instance
  }
}

// Usage in component
const { navigate, back } = useRouterNavigation()

Testing with Mock Router

typescript
import { routerKey } from 'vue-router'
import { createApp } from 'vue'

// Mock router for testing
const mockRouter = {
  push: vi.fn(),
  replace: vi.fn(),
  go: vi.fn(),
  back: vi.fn(),
  forward: vi.fn()
}

// Test setup helper
function setupTestWithRouter(component: any) {
  const app = createApp(component)
  app.provide(routerKey, mockRouter)
  return { app, mockRouter }
}

// Component test example
describe('RouterAwareComponent', () => {
  it('should navigate when button clicked', async () => {
    const { app, mockRouter } = setupTestWithRouter(TestComponent)
    
    const wrapper = mount(app)
    await wrapper.find('button').trigger('click')
    
    expect(mockRouter.push).toHaveBeenCalledWith('/target')
  })
})

🚨 Important Considerations

Injection Context Requirements

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

const router = inject(routerKey) // Works in setup context
</script>

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

Provider Setup

typescript
// The router must be provided at the app level
import { createApp } from 'vue'
import { createRouter, routerKey } from 'vue-router'

const router = createRouter({ /* config */ })
const app = createApp(App)

// Router is automatically provided by Vue Router
// But you can also provide it manually if needed
app.provide(routerKey, router)
  • routeLocationKey - Injection key for current route location
  • matchedRouteKey - Injection key for matched route
  • Vue Dependency Injection - Vue's provide/inject system

📚 Best Practices

Safe Router Access Pattern

typescript
class SafeRouterAccess {
  // Always check if router is available
  static ensureRouter(router: Router | undefined): Router {
    if (!router) {
      throw new Error(
        'Router instance is not available. ' +
        'Make sure your component is properly initialized.'
      )
    }
    return router
  }
  
  // Graceful navigation with error handling
  static async safeNavigate(
    router: Router | undefined, 
    to: RouteLocationRaw
  ): Promise<boolean> {
    try {
      const actualRouter = this.ensureRouter(router)
      await actualRouter.push(to)
      return true
    } catch (error) {
      console.error('Navigation failed:', error)
      return false
    }
  }
}

Router Injection Utility

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

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

💡 Pro Tip: Use routerKey for type-safe router injection in custom components and services. For most components, prefer using useRouter() from Vue Router's composition API as it's simpler and more straightforward.

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