Skip to content

RouteLocation Interface | Vue Router

RouteLocation is a core interface that represents a route location in various formats. It serves as the base type for different route location representations used throughout Vue Router. 📍

📋 Interface Definition

typescript
interface RouteLocation extends RouteLocationBase {
  // Route identification
  readonly name?: RouteRecordName | null | undefined
  readonly path: string
  readonly params: RouteParams
  
  // Additional properties
  readonly redirectedFrom?: RouteLocation | undefined
  readonly meta?: RouteMeta
}

🎯 Purpose and Usage

The RouteLocation interface provides a flexible representation of route locations that can be used for navigation, route matching, and route information storage. It's designed to accommodate different route location formats while maintaining type safety.

Key Characteristics:

  • Flexible Format - Supports both path-based and name-based routing
  • Type Safety - Full TypeScript support with proper typing
  • Navigation Ready - Suitable for use in navigation methods
  • Extensible - Can be extended for specific use cases

🔍 Property Details

Core Identification Properties

name - Route Name

The name of the route if using named routes.

typescript
// For named route navigation
const routeLocation: RouteLocation = {
  name: 'user-profile',
  params: { id: '123' }
}

path - Route Path

The path string for the route location.

typescript
// For path-based navigation
const routeLocation: RouteLocation = {
  path: '/user/123',
  params: {} // Can be empty for path-based navigation
}

params - Route Parameters

Dynamic parameters for the route.

typescript
// With parameters
const routeLocation: RouteLocation = {
  path: '/user/:id',
  params: { id: '123' }
}

Additional Properties

redirectedFrom - Redirect Source

If this route was reached via a redirect, contains the original route.

typescript
// After redirect from /old-path to /new-path
const routeLocation: RouteLocation = {
  path: '/new-path',
  redirectedFrom: { path: '/old-path' }
}

meta - Route Metadata

Custom metadata associated with the route.

typescript
const routeLocation: RouteLocation = {
  path: '/admin',
  meta: { requiresAuth: true, adminOnly: true }
}

💡 Practical Usage Examples

Programmatic Navigation

typescript
import type { RouteLocation } from 'vue-router'

// Different ways to specify route locations
const navigationExamples: RouteLocation[] = [
  // Path-based navigation
  { path: '/home' },
  
  // Path with parameters
  { path: '/user/:id', params: { id: '123' } },
  
  // Named route navigation
  { name: 'user-profile', params: { id: '123' } },
  
  // With query parameters (inherited from RouteLocationBase)
  { 
    path: '/search', 
    query: { q: 'vue router' },
    hash: '#results'
  },
  
  // With meta information
  { 
    path: '/premium', 
    meta: { requiresSubscription: true }
  }
]

// Using in navigation
async function navigateToUserProfile(userId: string) {
  const location: RouteLocation = {
    name: 'user-profile',
    params: { id: userId }
  }
  
  await router.push(location)
}

Route Location Creation Utilities

typescript
class RouteLocationFactory {
  // Create route location for user profile
  static createUserProfileLocation(userId: string): RouteLocation {
    return {
      name: 'user-profile',
      params: { id: userId },
      meta: { userSection: true }
    }
  }
  
  // Create route location for search results
  static createSearchLocation(query: string, filters?: SearchFilters): RouteLocation {
    const location: RouteLocation = {
      path: '/search',
      query: { q: query }
    }
    
    if (filters) {
      Object.assign(location.query!, filters)
    }
    
    return location
  }
  
  // Create route location with breadcrumb information
  static createLocationWithBreadcrumb(
    target: RouteLocation, 
    breadcrumbTitle: string
  ): RouteLocation {
    return {
      ...target,
      meta: {
        ...target.meta,
        breadcrumb: breadcrumbTitle
      }
    }
  }
}

Route Location Validation

typescript
class RouteLocationValidator {
  static isValidRouteLocation(location: any): location is RouteLocation {
    if (!location || typeof location !== 'object') {
      return false
    }
    
    // Must have either name or path
    if (!location.name && !location.path) {
      return false
    }
    
    // If has path, it must be a string
    if (location.path && typeof location.path !== 'string') {
      return false
    }
    
    // If has name, it must be string, symbol, or null/undefined
    if (location.name && typeof location.name !== 'string' && 
        typeof location.name !== 'symbol' && location.name !== null) {
      return false
    }
    
    // Params must be object if present
    if (location.params && typeof location.params !== 'object') {
      return false
    }
    
    return true
  }
  
  static validateForNavigation(location: RouteLocation): ValidationResult {
    const errors: string[] = []
    
    // Check required parameters for named routes
    if (location.name) {
      const route = router.getRoutes().find(r => r.name === location.name)
      if (route) {
        const requiredParams = this.getRequiredParams(route.path)
        for (const param of requiredParams) {
          if (!location.params || !(param in location.params)) {
            errors.push(`Missing required parameter: ${param}`)
          }
        }
      }
    }
    
    // Validate path format
    if (location.path && !location.path.startsWith('/')) {
      errors.push('Path must start with /')
    }
    
    return { isValid: errors.length === 0, errors }
  }
}

🔧 Advanced Patterns

Route Location Transformation

typescript
class RouteLocationTransformer {
  // Add query parameters to existing location
  static withQuery(
    location: RouteLocation, 
    query: Record<string, string>
  ): RouteLocation {
    return {
      ...location,
      query: { ...location.query, ...query }
    }
  }
  
  // Add hash fragment
  static withHash(location: RouteLocation, hash: string): RouteLocation {
    return {
      ...location,
      hash: hash.startsWith('#') ? hash : `#${hash}`
    }
  }
  
  // Convert between name-based and path-based locations
  static toPathBased(location: RouteLocation): RouteLocation {
    if (location.path) {
      return location // Already path-based
    }
    
    if (location.name) {
      // Resolve named route to path
      const route = router.getRoutes().find(r => r.name === location.name)
      if (route) {
        let path = route.path
        // Replace parameters in path
        if (location.params) {
          for (const [key, value] of Object.entries(location.params)) {
            path = path.replace(`:${key}`, value as string)
          }
        }
        return { path, params: location.params }
      }
    }
    
    throw new Error('Cannot convert to path-based location')
  }
  
  // Create relative location from current route
  static createRelativeLocation(relativePath: string): RouteLocation {
    const currentPath = router.currentRoute.value.path
    const newPath = currentPath.endsWith('/') 
      ? currentPath + relativePath 
      : currentPath + '/' + relativePath
    return { path: newPath }
  }
}

Route Location Comparison

typescript
class RouteLocationComparator {
  // Check if two locations are equivalent
  static areEquivalent(loc1: RouteLocation, loc2: RouteLocation): boolean {
    if (loc1.name && loc2.name) {
      return loc1.name === loc2.name && 
             this.areParamsEquivalent(loc1.params, loc2.params)
    }
    
    if (loc1.path && loc2.path) {
      return this.normalizePath(loc1.path) === this.normalizePath(loc2.path) &&
             this.areParamsEquivalent(loc1.params, loc2.params)
    }
    
    return false
  }
  
  // Check if location is active (current route)
  static isActiveLocation(location: RouteLocation): boolean {
    const currentRoute = router.currentRoute.value
    
    if (location.name && currentRoute.name) {
      return location.name === currentRoute.name
    }
    
    if (location.path) {
      return this.normalizePath(location.path) === 
             this.normalizePath(currentRoute.path)
    }
    
    return false
  }
  
  private static areParamsEquivalent(params1?: RouteParams, params2?: RouteParams): boolean {
    if (!params1 && !params2) return true
    if (!params1 || !params2) return false
    
    const keys1 = Object.keys(params1)
    const keys2 = Object.keys(params2)
    
    if (keys1.length !== keys2.length) return false
    
    return keys1.every(key => params1[key] === params2[key])
  }
}

🚨 Important Considerations

typescript
// RouteLocation is compatible with all navigation methods
const location: RouteLocation = {
  name: 'user-profile',
  params: { id: '123' }
}

// All these work with RouteLocation
router.push(location)
router.replace(location)
router.resolve(location)

// Also works with raw objects that match the interface
router.push({
  path: '/search',
  query: { q: 'test' }
})

Type Safety with Route Meta

typescript
// For better type safety, extend the RouteMeta interface
declare module 'vue-router' {
  interface RouteMeta {
    requiresAuth?: boolean
    pageTitle?: string
    breadcrumb?: string
    // Add your custom meta properties here
  }
}

// Now TypeScript will validate meta property access
const location: RouteLocation = {
  path: '/admin',
  meta: {
    requiresAuth: true,
    pageTitle: 'Admin Dashboard'
    // TypeScript error for unknown properties:
    // unknownProp: true // Error!
  }
}

📚 Best Practices

Route Location Creation Patterns

typescript
// ✅ Good: Use factory functions for common locations
const userLocations = {
  profile: (userId: string) => ({
    name: 'user-profile',
    params: { id: userId }
  }),
  settings: (userId: string) => ({
    name: 'user-settings', 
    params: { id: userId }
  })
}

// ✅ Good: Validate locations before navigation
async function safeNavigate(location: RouteLocation) {
  const validation = RouteLocationValidator.validateForNavigation(location)
  if (!validation.isValid) {
    throw new Error(`Invalid route location: ${validation.errors.join(', ')}`)
  }
  
  await router.push(location)
}

// ❌ Avoid: Creating locations with inconsistent data
const badLocation = {
  name: 'user-profile',
  path: '/user/123' // Conflicting information
}

Error Handling

typescript
class RouteLocationErrorHandler {
  static handleNavigationError(error: any, location: RouteLocation) {
    console.error('Navigation failed for location:', location)
    console.error('Error details:', error)
    
    // Provide user-friendly feedback based on error type
    if (error instanceof NavigationFailure) {
      this.handleNavigationFailure(error, location)
    } else {
      this.handleGenericError(error, location)
    }
  }
  
  private static handleNavigationFailure(failure: NavigationFailure, location: RouteLocation) {
    // Specific handling based on failure type
    switch (failure.type) {
      case NavigationFailureType.ABORTED:
        this.showAccessDeniedMessage(location)
        break
      case NavigationFailureType.CANCELLED:
        // Usually no user feedback needed
        break
      default:
        this.showGenericNavigationError()
    }
  }
}

💡 Pro Tip: Use RouteLocation for type-safe route navigation throughout your application. Factory functions and validation utilities can help maintain consistency and prevent navigation errors.

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