5.5 KiB
5.5 KiB
Vue Router Patterns Reference
Table of Contents
- Route Structure
- Route Groups
- File Naming Patterns
- Route Params Best Practices
- Navigation with Type Safety
- Using Route Data in Components
- definePage() Customization
- Typed Router Reference
- Route Layouts
- Navigation Guards (Per-Route)
- Fetch Route Data
Route Structure
File-based routing using unplugin-vue-router or similar.
✅ CORRECT:
src/pages/
(home).vue # Route groups for meaningful names
users.edit.vue # Use . for / without nesting
users.vue # Layout for users/*
users/
(user-list).vue # Group instead of index.vue
[userId].vue # Explicit param names
posts.[[slug]]+.vue # Optional repeatable params
❌ WRONG:
src/pages/
index.vue # Use groups: (home).vue
users/
index.vue # Use groups: (user-list).vue
[id].vue # Too generic: use [userId].vue
Rules:
- AVOID
index.vue→ use route groups(descriptive-name).vue - Use explicit param names:
[userId]not[id],[postSlug]not[slug] - Use
.in filenames for/without route nesting:users.edit.vue→/users/edit - Use
[[param]]for optional params,[param]+for repeatable - Prefer named routes with typed parameters over string URLs
Route Groups
Route groups create shared layouts without affecting URLs:
src/pages/
├── (admin).vue # Layout for all admin routes
├── (admin)/
│ ├── dashboard.vue # URL: /dashboard
│ └── settings.vue # URL: /settings
└── (user)/
├── profile.vue # URL: /profile
└── orders.vue # URL: /orders
The (admin).vue and (user).vue files provide layouts but don't add URL segments.
File Naming Patterns
Pattern URL Notes
─────────────────────────────────────────────────────────────
(home).vue / Root route with group
about.vue /about Simple route
users.vue /users Layout for nested routes
users/[userId].vue /users/:userId Dynamic param
users.edit.vue /users/edit Dot creates sibling
posts/[...slug].vue /posts/* Catch-all
settings.[[tab]].vue /settings/:tab? Optional param
docs.[[path]]+.vue /docs/:path+ Repeatable param
Route Params Best Practices
// ✅ CORRECT: Explicit, semantic param names
pages/
users/[userId].vue
posts/[postSlug].vue
orders/[orderId].vue
// ❌ WRONG: Generic names
pages/
users/[id].vue // Which ID? User? Post? Order?
posts/[slug].vue // Could be any entity
Navigation with Type Safety
import { useRouter } from 'vue-router/auto'
const router = useRouter()
// ✅ CORRECT: Named route with typed params
router.push({
name: '/users/[userId]',
params: { userId: 123 }
})
// ❌ WRONG: String concatenation (no type safety)
router.push('/users/' + userId)
// ✅ CORRECT: Query params
router.push({
name: '/search',
query: { q: 'vue', page: 2 }
})
Using Route Data in Components
<script setup lang="ts">
import { useRoute } from 'vue-router/auto'
// ✅ CORRECT: Pass route name for strict typing
const route = useRoute('/users/[userId]')
// Now route.params.userId is typed as string
const userId = route.params.userId
// ✅ CORRECT: Access query params
const searchQuery = route.query.q
</script>
definePage() Customization
<script setup lang="ts">
definePage({
name: 'UserProfile',
meta: {
requiresAuth: true,
title: 'User Profile'
},
alias: ['/profile'],
redirect: (to) => {
// Conditional redirect
if (!to.params.userId) {
return { name: '/users' }
}
}
})
</script>
Typed Router Reference
Always refer to typed-router.d.ts for:
- Available route names
- Required/optional params
- Query param types
// typed-router.d.ts is auto-generated
// Check it for available routes and their params
Route Layouts
src/pages/
├── users.vue # Parent layout
└── users/
├── (list).vue # Renders inside users.vue
└── [userId]/
├── (details).vue # Renders inside users.vue
└── edit.vue # Renders inside users.vue
users.vue contains <RouterView /> for nested routes.
Navigation Guards (Per-Route)
<script setup lang="ts">
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
onBeforeRouteLeave((to, from) => {
if (hasUnsavedChanges.value) {
const answer = window.confirm('Discard unsaved changes?')
if (!answer) return false
}
})
onBeforeRouteUpdate(async (to, from) => {
// Called when route params change but same component reused
if (to.params.userId !== from.params.userId) {
await loadUser(to.params.userId)
}
})
</script>
Fetch Route Data
For up-to-date routing documentation with unplugin-vue-router: https://uvr.esm.is/llms.txt
Follow links in that file for:
- Advanced route patterns
- Type-safe navigation
- Meta fields
- Route guards