Skip to content

START_LOCATION Variable | Vue Router

START_LOCATION is a special constant that represents the initial route location when the router is first initialized. This value is used internally by Vue Router and can be useful for detecting initial navigation states. 🚦

📋 Variable Definition

typescript
const START_LOCATION: RouteLocationNormalized

🎯 Purpose and Usage

The START_LOCATION constant serves as a marker for the router's initial state before any navigation occurs. It's particularly useful for:

  • Initialization Detection - Determining if the router is in its starting state
  • Navigation Comparison - Comparing current route with the initial state
  • Guard Logic - Special handling for the very first navigation

🔍 Technical Details

Internal Representation

START_LOCATION is a normalized route object with specific properties that indicate it's the initial state:

typescript
// Simplified internal structure
const START_LOCATION = {
  path: '/',
  fullPath: '/',
  hash: '',
  query: {},
  params: {},
  name: undefined,
  matched: [],
  meta: {},
  href: '/'
}

Key Characteristics

  • Path: Always '/' (root path)
  • Empty State: All collections (params, query, meta) are empty
  • No Matches: matched array is empty since no routes are matched yet
  • Internal Use: Primarily used internally by Vue Router

💡 Practical Usage Examples

Detecting Initial Navigation

typescript
import { START_LOCATION } from 'vue-router'
import { useRoute } from 'vue-router'

const route = useRoute()

// Check if this is the very first navigation
const isInitialNavigation = computed(() => 
  route.fullPath === START_LOCATION.fullPath
)

// Use in component lifecycle
onMounted(() => {
  if (route.fullPath === START_LOCATION.fullPath) {
    console.log('Component mounted during initial navigation')
    // Perform initialization logic
  }
})
typescript
import { START_LOCATION } from 'vue-router'

router.beforeEach((to, from) => {
  // Special handling for initial navigation
  if (from === START_LOCATION) {
    console.log('This is the first navigation in the app')
    
    // You might want different behavior for initial navigation
    if (to.meta.requiresInitialSetup) {
      return '/welcome' // Redirect first-time users
    }
  }
  
  // Normal guard logic for subsequent navigations
  if (to.meta.requiresAuth && !isAuthenticated()) {
    return '/login'
  }
})

Analytics and Tracking

typescript
import { START_LOCATION } from 'vue-router'

router.afterEach((to, from) => {
  // Track navigation events
  if (from === START_LOCATION) {
    // This is the app's first navigation
    analytics.track('app_initial_navigation', {
      target: to.path,
      timestamp: Date.now()
    })
  } else {
    // Normal navigation between pages
    analytics.track('page_navigation', {
      from: from.path,
      to: to.path,
      timestamp: Date.now()
    })
  }
})

🔧 Advanced Usage Patterns

Initialization State Management

typescript
class AppInitialization {
  private isInitialized = false
  
  setupNavigationTracking(router: Router) {
    router.afterEach((to, from) => {
      if (from === START_LOCATION && !this.isInitialized) {
        this.handleInitialNavigation(to)
        this.isInitialized = true
      }
    })
  }
  
  private handleInitialNavigation(initialRoute: RouteLocationNormalized) {
    console.log('App initialized with route:', initialRoute.path)
    
    // Perform one-time initialization tasks
    this.loadEssentialData()
    this.setupServiceWorker()
    this.initializeThirdPartyServices()
  }
}

Route Comparison Utility

typescript
function createRouteComparator(router: Router) {
  const initialRoute = START_LOCATION
  
  return {
    isInitialRoute(route: RouteLocationNormalized): boolean {
      return route.fullPath === initialRoute.fullPath
    },
    
    hasRouteChanged(from: RouteLocationNormalized, to: RouteLocationNormalized): boolean {
      // Special case: initial navigation always counts as a change
      if (from === initialRoute) return true
      
      // Normal route change detection
      return from.fullPath !== to.fullPath
    },
    
    getNavigationType(from: RouteLocationNormalized, to: RouteLocationNormalized): string {
      if (from === initialRoute) return 'initial'
      if (from.path === to.path) return 'same-route'
      return 'cross-route'
    }
  }
}

Progressive Web App Integration

typescript
class PWAIntegration {
  constructor(private router: Router) {
    this.setupAppShellNavigation()
  }
  
  private setupAppShellNavigation() {
    this.router.afterEach((to, from) => {
      // Special handling for app shell initialization
      if (from === START_LOCATION) {
        this.initializeAppShell()
        this.prefetchCriticalResources()
      }
    })
  }
  
  private initializeAppShell() {
    // Initialize app shell components
    // Set up service worker communication
    // Prepare offline capabilities
    console.log('App shell initialized')
  }
  
  private prefetchCriticalResources() {
    // Prefetch resources needed for smooth navigation
    // based on common user paths
  }
}

🚨 Important Considerations

Equality Comparison

typescript
import { START_LOCATION } from 'vue-router'

const route = useRoute()

// ✅ Correct - compare with START_LOCATION constant
if (route.fullPath === START_LOCATION.fullPath) {
  // Handle initial state
}

// ❌ Incorrect - creating new objects for comparison
if (route.fullPath === '/') {
  // This might not detect START_LOCATION correctly in all cases
}

// ✅ Correct - using the provided constant
if (route === START_LOCATION) {
  // Direct comparison works because START_LOCATION is a singleton
}

Reactivity and Timing

typescript
import { START_LOCATION } from 'vue-router'
import { onMounted, ref } from 'vue'

const route = useRoute()
const isInitialLoad = ref(true)

onMounted(() => {
  // By the time onMounted runs, navigation might have already occurred
  // START_LOCATION comparison might not work as expected here
  
  // Better approach: use navigation guards or watch route changes
})

// More reliable approach
watch(() => route.fullPath, (newPath, oldPath) => {
  if (oldPath === START_LOCATION.fullPath) {
    console.log('Initial navigation completed')
    isInitialLoad.value = false
  }
}, { immediate: true })
  • Navigation Guards - Where START_LOCATION comparisons are commonly used
  • Router Initialization - The process that creates START_LOCATION

📚 Use Case Scenarios

1. Splash Screen Management

typescript
class SplashScreenManager {
  private router: Router
  private showSplash = ref(true)
  
  constructor(router: Router) {
    this.router = router
    this.setupNavigationTracking()
  }
  
  private setupNavigationTracking() {
    this.router.afterEach((to, from) => {
      // Hide splash screen after initial navigation
      if (from === START_LOCATION && this.showSplash.value) {
        setTimeout(() => {
          this.showSplash.value = false
        }, 1000) // Keep splash visible for 1 second
      }
    })
  }
  
  get shouldShowSplash() {
    return this.showSplash.value
  }
}

2. Authentication Flow

typescript
function setupAuthNavigation(router: Router) {
  router.beforeEach((to, from) => {
    // Special handling for initial navigation to protected routes
    if (from === START_LOCATION && to.meta.requiresAuth) {
      // If app starts on a protected route, redirect to login
      // but remember the intended destination
      return {
        path: '/login',
        query: { redirect: to.fullPath }
      }
    }
    
    // Normal auth check for subsequent navigations
    if (to.meta.requiresAuth && !isAuthenticated()) {
      return '/login'
    }
  })
}

3. Performance Monitoring

typescript
class PerformanceMonitor {
  private initialLoadTime: number | null = null
  
  constructor(router: Router) {
    this.setupNavigationMonitoring(router)
  }
  
  private setupNavigationMonitoring(router: Router) {
    const navigationStart = performance.now()
    
    router.afterEach((to, from) => {
      if (from === START_LOCATION) {
        const loadTime = performance.now() - navigationStart
        this.initialLoadTime = loadTime
        
        console.log(`Initial app load time: ${loadTime}ms`)
        this.reportInitialLoadPerformance(loadTime)
      }
    })
  }
}

💡 Pro Tip: While START_LOCATION is useful for detecting initial states, most application logic should work correctly regardless of whether it's the first navigation or subsequent ones. Use it sparingly for special initialization cases.

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