Day 4 of 5
⏱ ~60 minutes
Vue.js in 5 Days — Day 4

Vue Router: Multi-Page Apps

Real apps have multiple pages. Vue Router handles client-side navigation without full page reloads. This lesson covers setting up routes, dynamic route parameters, protecting routes, and lazy-loading components for faster initial loads.

Installing and Configuring Vue Router

Terminal
npm install vue-router
src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'

// Import page components
import HomeView from '@/views/HomeView.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    // Lazy-load: only downloaded when the route is visited
    component: () => import('@/views/AboutView.vue')
  },
  {
    path: '/users/:id',  // :id is a dynamic segment
    name: 'user-detail',
    component: () => import('@/views/UserDetailView.vue')
  },
  {
    // 404 catch-all — must be last
    path: '/:pathMatch(.*)*',
    name: 'not-found',
    component: () => import('@/views/NotFoundView.vue')
  }
]

const router = createRouter({
  history: createWebHistory(),  // uses real URLs (no #)
  routes
})

export default router
src/main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import router from './router'
import App from './App.vue'

createApp(App).use(createPinia()).use(router).mount('#app')

RouterView and RouterLink

src/App.vue




Dynamic Routes and useRoute

Dynamic route segments like :id let one route match many URLs. Access the current route's params, query, and path with useRoute().

src/views/UserDetailView.vue


Navigation Guards: Protecting Routes

Navigation guards run code before a route is entered — perfect for authentication checks.

src/router/index.js (with auth guard)
import { useAuthStore } from '@/stores/auth'

// Per-route guard using route metadata
const routes = [
  {
    path: '/dashboard',
    component: () => import('@/views/DashboardView.vue'),
    meta: { requiresAuth: true }  // mark protected routes
  }
]

// Global guard: runs before every navigation
router.beforeEach((to, from) => {
  const auth = useAuthStore()

  if (to.meta.requiresAuth && !auth.isLoggedIn) {
    // Redirect to login, saving where they wanted to go
    return { name: 'login', query: { redirect: to.fullPath } }
  }
})
💡
After login: redirect the user to route.query.redirect || '/' so they land on the page they originally tried to visit. This is the expected UX pattern.
📝 Day 4 Exercise
Build a Multi-Page User Directory
  1. Set up Vue Router with at least 4 routes: Home, Users list, User detail (/users/:id), and 404.
  2. Fetch the users list from https://jsonplaceholder.typicode.com/users and display them on the Users page.
  3. Each user should be a link to their detail page. On the detail page, fetch and show their posts too.
  4. Build a persistent navbar with RouterLink and active link styling.
  5. Add a navigation guard that logs every route change to the console.
  6. Add a 404 page that shows the attempted path and a 'Go Home' button.

Day 4 Summary

  • Vue Router handles client-side navigation — fast page switches without full reloads.
  • Lazy-load routes with () => import('./View.vue') for better initial load performance.
  • Dynamic segments like :id let one route serve many URLs. Read them with useRoute().params.
  • Navigation guards run before route changes — use them for auth checks.
  • Use router.push() for programmatic navigation, RouterLink in templates.
Finished this lesson?