Vue Router

Target: pemula yang sudah memahami dasar Vue 3 (component, template, props, emit, Composition API), lalu ingin belajar routing multi-halaman dengan Vue Router. Versi: Vue Router 4.x / Vue 3.x Prasyarat: Vue Dasar Fokus modul pembelajaran ini: pengenalan SPA → setup & instalasi → RouterLink & RouterView → routes dasar → route params → matching syntax → query params → programmatic navigation → nested routes → named routes → named views → redirect & alias → props → history modes → lazy loading → meta → navigation guards → router view slot → scroll behavior → dynamic routing → mini project. Semua contoh utama menggunakan Vue 3 + Composition API (<script setup>) dan Vue Router 4. API Vue Router 4 menggunakan createRouter() dan opsi history, bukan sintaks new Router() / mode lama milik Vue Router 3.


Cara Belajar

🟢 Fundamental
→ wajib dipahami untuk mulai membuat aplikasi multi-halaman
 
🟡 Lanjutan
→ pelajari setelah routing dasar dan parameter nyaman
 
🔴 Advanced / Reference
→ penting ketika kebutuhan aplikasi, proteksi rute, dan performa meningkat

Mental model:

       URL di Browser Bar

               │ dicocokkan oleh Router

       Route Matching & Params

               │ validasi akses

       Navigation Guards

               │ render component yang cocok

       <RouterView />


       Tampilan UI Terupdate

Hafalan:

Vue        → membangun komponen antarmuka (UI)
Vue Router → mengatur URL, navigasi, dan perpindahan halaman

Daftar Isi

🟢 Fundamental

  1. Pengenalan SPA & Routing
  2. Setup & Instalasi Vue Router
  3. Komponen Router: RouterLink & RouterView
  4. Konfigurasi Routes Dasar
  5. Dynamic Route Matching (Route Params)
  6. Matching Syntax Lanjutan
  7. Query Params & Hash
  8. Programmatic Navigation (useRouter)

🟡 Lanjutan

  1. Nested Routes (Rute Bersarang)
  2. Named Routes
  3. Named Views
  4. Redirect & Alias
  5. Passing Props ke Route Component
  6. History Modes
  7. Lazy Loading Routes
  8. Route Meta Fields
  9. Navigation Guards (Proteksi Rute)
  10. RouterView Slot, Transition & KeepAlive
  11. Scroll Behavior
  12. Dynamic Routing

🔴 Advanced / Reference

  1. Navigation Failure Handling
  2. Peta Ingatan Cepat
  3. Tabel Ringkasan
  4. Cheat Code Vue Router 10 Detik
  5. Urutan Belajar yang Disarankan
  6. Mini Project: Portal Dashboard Pengguna
  7. Referensi Resmi

1. 🟢 Pengenalan SPA & Routing

Konsep

SPA (Single Page Application) adalah aplikasi web yang hanya memuat satu file HTML utama (index.html) lalu mengganti tampilan komponen secara dinamis berdasarkan URL tanpa melakukan full page reload (layar putih berkedip).

Perbandingan: Web Tradisional vs Vue Router SPA

Web Tradisional (Multi-Page Reload)
       Pengguna Klik Link

               │ browser request file baru ke server

       Server Memproses & Mengirim HTML Baru

               │ browser memuat ulang seluruh halaman

       Full Page Reload (Layar Putih Berkedip)
Vue Router SPA (Instant Client-Side Navigation)
       Pengguna Klik <RouterLink>

               │ router mencegat event klik di browser

       URL di Address Bar Berubah

               │ router mencocokkan route path

       Komponen Halaman Ditukar di dalam <RouterView />


       UI Berubah Instan Tanpa Reload Server

Struktur Aplikasi Vue Router

       App.vue (Layout Utama)

          │ <RouterView />

       ┌───────────────────────────────┐
       │ /         ──> HomeView.vue    │
       │ /about    ──> AboutView.vue   │
       │ /users/10 ──> UserView.vue    │
       └───────────────────────────────┘

Hafalan:

Router menghubungkan: URL di browser ──> Komponen Vue yang dirender

Best Practice: Gunakan <RouterLink> untuk navigasi internal aplikasi. Jangan gunakan <a href> biasa karena akan memicu full page reload yang merusak pengalaman SPA.


2. 🟢 Setup & Instalasi Vue Router

Konsep

Vue Router diinstal melalui package manager dan didaftarkan sebagai plugin ke aplikasi Vue menggunakan createRouter() dan app.use(router).

1. Instalasi

Jalankan perintah di terminal:

npm install vue-router

2. Membuat Konfigurasi Router (src/router/index.js)

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '@/views/HomeView.vue'
import AboutView from '@/views/AboutView.vue'
 
const routes = [
  { path: '/', component: HomeView },
  { path: '/about', component: AboutView },
]
 
const router = createRouter({
  history: createWebHistory(),
  routes,
})
 
export default router

3. Daftarkan di Entry Point (src/main.js)

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
 
const app = createApp(App)
 
// Pasang router sebelum mount
app.use(router)
 
app.mount('#app')

Diagram Alur Setup

       createApp(App)

             │ buat aplikasi Vue

       createRouter({ history, routes })

             │ inisialisasi konfigurasi router

       app.use(router)

             │ daftarkan plugin router

       app.mount('#app')


       Aplikasi Siap Melakukan Routing

Hafalan:

createRouter() → app.use(router) → pasang <RouterView /> di App.vue

Konsep

Vue Router menyediakan dua komponen global utama:

  1. <RouterLink>: Komponen navigasi deklaratif (menggantikan tag <a>).
  2. <RouterView>: Wadah tempat komponen rute ditampilkan sesuai URL aktif.

Contoh Penggunaan (src/App.vue)

<template>
  <div id="app">
    <nav class="navbar">
      <RouterLink to="/">Beranda</RouterLink>
      <RouterLink to="/about">Tentang Kami</RouterLink>
    </nav>
 
    <main class="content">
      <!-- Komponen rute akan dirender di sini -->
      <RouterView />
    </main>
  </div>
</template>
 
<style scoped>
/* Kelas CSS otomatis untuk link yang sedang aktif */
.router-link-active {
  font-weight: bold;
  color: #42b883;
}
.router-link-exact-active {
  border-bottom: 2px solid #42b883;
}
</style>

Diagram Alur Navigasi

       Klik <RouterLink to="/about">

                       │ ubah URL tanpa reload

             Address Bar: /about

                       │ router mencocokkan path

           AboutView Dimuat di <RouterView />

Vue Router secara otomatis menambahkan kelas CSS pada <RouterLink> yang aktif:

  • router-link-active: Aktif jika URL saat ini mengandung path tujuan (misal /about cocok dengan /about/team).
  • router-link-exact-active: Aktif hanya jika URL saat ini persis 100% sama dengan atribut to.

Hafalan:

RouterLink → tombol pindah halaman (menggantikan <a>)
RouterView → slot penampil halaman rute aktif

4. 🟢 Konfigurasi Routes Dasar

Konsep

Array routes mendefinisikan pemetaan antara alamat URL (path) dan komponen Vue (component) yang akan ditampilkan.

Contoh Konfigurasi Rute

import HomeView from '@/views/HomeView.vue'
import AboutView from '@/views/AboutView.vue'
import ContactView from '@/views/ContactView.vue'
import NotFoundView from '@/views/NotFoundView.vue'
 
const routes = [
  { path: '/', component: HomeView },
  { path: '/about', component: AboutView },
  { path: '/contact', component: ContactView },
 
  // Catch-all route untuk halaman 404 (Not Found)
  { path: '/:pathMatch(.*)*', component: NotFoundView },
]

Output Alur

Buka URL: /         ──> Merender HomeView
Buka URL: /about    ──> Merender AboutView
Buka URL: /contact  ──> Merender ContactView
Buka URL: /ngawur   ──> Merender NotFoundView (404)

Diagram Penanganan 404

       URL yang Diminta Pengguna

                   │ cocok dengan salah satu route?
         ┌─────────┴─────────┐
         │ YA                │ TIDAK
         ▼                   ▼
    Halaman Terkait    /:pathMatch(.*)*


                   NotFoundView (404)

Hafalan:

path: '/' ──> URL tujuan
component: NamaView ──> Komponen yang dirender
/:pathMatch(.*)* ──> Penampung halaman 404

Best Practice: Selalu letakkan route 404 /:pathMatch(.*)* di baris paling akhir array routes.


5. 🟢 Dynamic Route Matching (Route Params)

Konsep

Ketika sebuah rute memiliki bagian dinamis (seperti ID pengguna atau slug artikel), gunakan tanda titik dua : untuk mendefinisikan Route Params.

Contoh Konfigurasi

const routes = [
  // :id adalah parameter dinamis
  { path: '/users/:id', component: () => import('@/views/UserDetailView.vue') },
]

Membaca Parameter di Komponen (UserDetailView.vue)

Gunakan fungsi useRoute() dari vue-router untuk membaca data URL aktif:

<script setup>
import { useRoute } from 'vue-router'
 
const route = useRoute()
 
// Membaca nilai param id
console.log('ID User:', route.params.id)
</script>
 
<template>
  <div class="user-detail">
    <h1>Profil Pengguna #{{ route.params.id }}</h1>
  </div>
</template>

Output

Akses URL: /users/42   ──> Tampilan: "Profil Pengguna #42"
Akses URL: /users/andi ──> Tampilan: "Profil Pengguna #andi"

Diagram Alur Route Params

       URL: /users/42

             │ router mengekstrak bagian dinamis

       route.params = { id: '42' }

             │ dibaca di komponen

       Template: <h1>Profil Pengguna #42</h1>

Hafalan:

path: '/users/:id' ──> dibaca melalui route.params.id

6. 🟢 Matching Syntax Lanjutan

Konsep

Vue Router 4 mendukung sintaks pencocokan rute yang fleksibel menggunakan optional params, custom regex, dan repeatable params.

1. Optional Param (:param?)

Tambahkan tanda tanya ? jika parameter boleh ada atau tidak ada:

// Cocok untuk /users dan /users/10
{ path: '/users/:id?', component: UserView }

2. Custom Regex Param (:param(pattern))

Batasi format parameter agar hanya cocok dengan pola tertentu (misal hanya angka):

// Hanya cocok jika :id berupa angka (digit)
{ path: '/products/:id(\\d+)', component: ProductView }
/products/123  ──> Cocok (Halaman ProductView dirender)
/products/sepatu ──> Tidak cocok (Dilewati ke rute berikutnya / 404)

3. Repeatable Param (:param+ atau :param*)

Gunakan + (minimal 1 segmen) atau * (0 atau lebih segmen) untuk menangkap path bersarang:

// Cocok untuk /files/dokumen/2026/laporan.pdf
{ path: '/files/:chapters+', component: FileView }

Hasil ekstraksi:

route.params.chapters // ['dokumen', '2026', 'laporan.pdf']

Ringkasan Sintaks Matching

/users/:id        ──> Wajib ada 1 nilai
/users/:id?       ──> Opsional (boleh kosong)
/users/:id(\\d+)   ──> Wajib berupa angka
/files/:path+     ──> Berulang (1 atau lebih segmen jadi array)
/:pathMatch(.*)*  ──> Catch-all seluruh URL (404)

Hafalan:

? = opsional, (\\d+) = hanya angka, + / * = repeatable segmen

7. 🟢 Query Params & Hash

Konsep

Selain parameter path, URL sering kali membawa data tambahan berupa Query Params (?key=value) dan Hash (#section). Query dan hash bersifat opsional dan tidak mengubah struktur pencocokan rute.

Perbedaan Anatomi URL

https://example.com/products/10?category=laptop&sort=asc#spesifikasi
                    │          │                         │
                    │          │                         └── Hash: route.hash ('#spesifikasi')
                    │          └──────────────────────────── Query: route.query.category ('laptop')
                    └─────────────────────────────────────── Path: route.params.id ('10')

Membaca Query dan Hash di Komponen

<script setup>
import { useRoute } from 'vue-router'
 
const route = useRoute()
 
console.log('Path Param:', route.params.id)    // '10'
console.log('Kategori:', route.query.category)  // 'laptop'
console.log('Urutan:', route.query.sort)        // 'asc'
console.log('Hash ID:', route.hash)             // '#spesifikasi'
</script>
 
<template>
  <div>
    <p>Menampilkan produk kategori: {{ route.query.category }}</p>
  </div>
</template>
<RouterLink :to="{ path: '/products/10', query: { category: 'laptop' }, hash: '#spesifikasi' }">
  Lihat Spesifikasi Laptop
</RouterLink>

Hafalan:

/users/:id ──> route.params (struktur rute)
?tab=desc  ──> route.query (filter / pencarian)
#reviews   ──> route.hash (posisi anchor elemen)

8. 🟢 Programmatic Navigation (useRouter)

Konsep

Selain navigasi deklaratif menggunakan <RouterLink>, kita dapat berpindah halaman melalui kode JavaScript (misal setelah tombol submit form diklik) menggunakan fungsi useRouter().

Perbedaan Vital: useRouter() vs useRoute()

       ┌───────────────────────────────────────────────────────────┐
       │                Perbedaan useRouter vs useRoute            │
       ├─────────────────────────────┬─────────────────────────────┤
       │ useRouter()                 │ useRoute()                  │
       ├─────────────────────────────┼─────────────────────────────┤
       │ Objek CONTROLLER navigasi   │ Objek SNAPSHOT data rute    │
       │ Digunakan untuk BERPINDAH   │ Digunakan untuk MEMBACA     │
       │ router.push('/about')       │ route.params.id             │
       │ router.replace('/login')    │ route.query.search          │
       │ router.back() / router.go() │ route.path / route.meta     │
       └─────────────────────────────┴─────────────────────────────┘

Contoh Metode Navigasi

<script setup>
import { useRouter } from 'vue-router'
 
const router = useRouter()
 
function handleLoginSuccess() {
  // 1. Pindah ke halaman baru (menambah riwayat history browser)
  router.push('/dashboard')
 
  // 2. Navigasi dengan object & params
  // router.push({ name: 'user-profile', params: { id: '42' } })
 
  // 3. Ganti halaman saat ini tanpa menambah history (user tidak bisa klik tombol 'Back' browser)
  // router.replace('/home')
 
  // 4. Navigasi riwayat history
  // router.back() // Mundur 1 halaman
  // router.forward() // Maju 1 halaman
  // router.go(-2) // Mundur 2 halaman
}
</script>
 
<template>
  <button @click="handleLoginSuccess">Login & Masuk Dashboard</button>
</template>

Hafalan:

router.push('/path')    → pindah halaman (ada history)
router.replace('/path') → timpa halaman saat ini (tanpa history)
router.back()           → kembali ke halaman sebelumnya

9. 🟡 Nested Routes (Rute Bersarang)

Konsep

Aplikasi modern sering kali memiliki tata letak bertingkat (misal: halaman Dashboard yang memiliki sidebar tetap, dan area konten tengah berganti-ganti antara Profile, Settings, dan Analytics).

Pola ini dibangun menggunakan Nested Routes dengan properti children.

Konfigurasi Nested Routes

const routes = [
  {
    path: '/dashboard',
    component: () => import('@/views/DashboardLayout.vue'),
    children: [
      // URL: /dashboard
      { path: '', component: () => import('@/views/DashboardHome.vue') },
      // URL: /dashboard/profile
      { path: 'profile', component: () => import('@/views/DashboardProfile.vue') },
      // URL: /dashboard/settings
      { path: 'settings', component: () => import('@/views/DashboardSettings.vue') },
    ],
  },
]

Komponen Induk (DashboardLayout.vue)

Komponen induk wajib memiliki <RouterView /> untuk merender anak komponennya:

<template>
  <div class="dashboard-layout">
    <aside class="sidebar">
      <RouterLink to="/dashboard">Ringkasan</RouterLink>
      <RouterLink to="/dashboard/profile">Profil Saya</RouterLink>
      <RouterLink to="/dashboard/settings">Pengaturan</RouterLink>
    </aside>
 
    <main class="dashboard-content">
      <!-- Komponen anak (children) akan dirender di sini -->
      <RouterView />
    </main>
  </div>
</template>

Diagram Alur Nested Routes

       URL: /dashboard/profile


       DashboardLayout.vue (Parent)

                  │ <RouterView /> internal

       DashboardProfile.vue (Child)

Hafalan:

children: [ { path: 'sub-path', component: ChildView } ]
Parent wajib menyertakan <RouterView /> untuk merender child.

Kesalahan Umum:

❌ Menulis path anak dengan awalan slash / (misal: path: '/profile' di dalam children). Path yang diawali / akan dianggap sebagai root URL absolut!
✅ Tulis tanpa awalan slash: path: 'profile'.


10. 🟡 Named Routes

Konsep

Named Routes adalah memberikan nama unik (name) pada konfigurasi rute. Menggunakan nama jauh lebih aman dan fleksibel daripada menulis string path URL secara manual di banyak komponen.

Keuntungan Named Routes

  • Jika path URL berubah (misal dari /pengguna/:id menjadi /members/:id), kita hanya perlu mengubah 1 file router saja tanpa harus mengedit ratusan komponen lain.
  • Menghindari kesalahan ketik (typo) pada URL yang panjang.

Konfigurasi

const routes = [
  {
    path: '/user-profile-account/:userId',
    name: 'user-detail',
    component: UserDetailView,
  },
]

Cara Pemakaian

<RouterLink :to="{ name: 'user-detail', params: { userId: '123' } }">
  Lihat Profil
</RouterLink>
2. Di Script (router.push)
router.push({
  name: 'user-detail',
  params: { userId: '123' },
  query: { tab: 'settings' },
})

Hafalan:

name: 'namaUnik' → :to="{ name: 'namaUnik', params: { id: 1 } }"

11. 🟡 Named Views

Konsep

Secara default, satu <RouterView /> merender satu komponen. Namun, jika Anda memiliki tata letak dengan beberapa area independen (misalnya: Header, Sidebar, dan Main Content yang berbeda-beda per rute), Anda dapat menggunakan Named Views.

Konfigurasi Router

Gunakan properti components (jamak), bukan component:

const routes = [
  {
    path: '/dashboard',
    components: {
      default: MainContent,
      sidebar: AppSidebar,
      header: AppHeader,
    },
  },
]

Template Layout (App.vue)

<template>
  <div class="layout">
    <!-- Named View: header -->
    <RouterView name="header" />
 
    <div class="body">
      <!-- Named View: sidebar -->
      <RouterView name="sidebar" />
 
      <!-- Default View (tanpa atribut name) -->
      <RouterView />
    </div>
  </div>
</template>

Diagram Named Views

       URL: /dashboard

              ├──────> <RouterView name="header" />  ──> AppHeader.vue
              ├──────> <RouterView name="sidebar" /> ──> AppSidebar.vue
              └──────> <RouterView /> (default)     ──> MainContent.vue

Hafalan:

components: { default: A, sidebar: B } ──> <RouterView name="sidebar" />

12. 🟡 Redirect & Alias

Konsep

  • Redirect: Ketika pengguna membuka URL A, router otomatis mengarahkan browser ke URL B.
  • Alias: URL A dan URL B menampilkan komponen yang sama persis tanpa mengubah alamat URL di browser.

1. Redirect

const routes = [
  // Redirect string sederhana
  { path: '/home', redirect: '/' },
 
  // Redirect ke Named Route
  { path: '/profile', redirect: { name: 'user-profile' } },
 
  // Dynamic Redirect berbasis fungsi
  {
    path: '/users',
    redirect: (to) => {
      return { path: '/members', query: { from: to.path } }
    },
  },
]

2. Alias

const routes = [
  {
    path: '/users',
    component: UserListView,
    // /members dan /people akan menampilkan UserListView dengan URL tetap
    alias: ['/members', '/people'],
  },
]

Hafalan:

redirect: '/tujuan' ──> URL browser berubah ke tujuan baru
alias: '/nama-lain' ──> URL tetap nama lain, tapi komponen yang dimuat sama

13. 🟡 Passing Props ke Route Component

Konsep

Daripada komponen rute membaca $route.params.id secara langsung (yang membuat komponen terikat erat dengan Vue Router), kita dapat mengaktifkan props: true. Hal ini membuat komponen bersifat murni (decoupled) dan mudah diuji secara independen.

1. Boolean Mode (props: true)

const routes = [
  {
    path: '/users/:id',
    component: UserDetailView,
    props: true, // Otomatis mengoper route.params sebagai props komponen
  },
]

Di dalam Komponen (UserDetailView.vue):

<script setup>
// Menerima param langsung sebagai prop standar Vue!
defineProps({
  id: String,
})
</script>
 
<template>
  <h1>Pengguna ID: {{ id }}</h1>
</template>

2. Function Mode (props: (route) => ({ ... }))

Gunakan fungsi jika ingin menggabungkan query params atau melakukan casting tipe:

{
  path: '/search',
  component: SearchView,
  props: (route) => ({ query: route.query.q, page: Number(route.query.page) || 1 }),
}

Hafalan:

props: true ──> route.params otomatis diterima via defineProps()

14. 🟡 History Modes

Konsep

Vue Router 4 menyediakan tiga mode riwayat navigasi (history modes) yang dipilih saat membuat router melalui opsi history.

Perbandingan 3 History Mode

ModeFungsi PembuatFormat URLKebutuhan Konfigurasi Server
HTML5 History (Direkomendasikan)createWebHistory()example.com/aboutWajib URL rewrite ke index.html
Hash ModecreateWebHashHistory()example.com/#/aboutTidak perlu konfigurasi server
Memory ModecreateMemoryHistory()Tidak tampil di browserUntuk SSR / Testing / Node.js

Contoh Konfigurasi HTML5 Mode

import { createRouter, createWebHistory } from 'vue-router'
 
const router = createRouter({
  // Menghasilkan URL bersih dan modern tanpa tanda pagar #
  history: createWebHistory(),
  routes,
})

Penting: Pada mode createWebHistory(), jika pengguna menekan tombol refresh (F5) pada URL /about, server web (Nginx/Apache) harus dikonfigurasi untuk mengembalikan index.html, jika tidak maka akan terjadi error 404 dari web server.

Hafalan:

createWebHistory()     → URL bersih standar modern (SPA produksi)
createWebHashHistory() → URL dengan tanda # (demo tanpa setting server)
createMemoryHistory()  → URL di memori (testing & SSR)

15. 🟡 Lazy Loading Routes

Konsep

Secara default, jika semua komponen diimpor di awal file (import Home from './Home.vue'), seluruh kode halaman akan digabungkan menjadi satu file JavaScript raksasa.

Dengan Lazy Loading (Dynamic Import), kode sebuah halaman hanya akan diunduh oleh browser saat pengguna benar-benar membuka rute tersebut. Hal ini membuat waktu muat awal aplikasi (initial load time) jauh lebih cepat.

Cara Penulisan

const routes = [
  // Halaman utama dimuat langsung (eager)
  { path: '/', component: HomeView },
 
  // Halaman lain diimpor secara dinamis saat dibuka (lazy loaded)
  {
    path: '/about',
    component: () => import('@/views/AboutView.vue'),
  },
  {
    path: '/admin',
    component: () => import('@/views/AdminDashboard.vue'),
  },
]

Diagram Alur Lazy Loading

       Aplikasi Pertama Kali Dibuka


       Browser Hanya Mengunduh: Bundle Utama (HomeView)

                     │ pengguna klik /admin

       Browser Mengunduh Chunk Khusus: AdminDashboard.js


       Halaman Admin Dirender

Hafalan:

component: () => import('@/views/NamaView.vue') ──> kode diunduh saat dibutuhkan

16. 🟡 Route Meta Fields

Konsep

Properti meta memungkinkan kita menyematkan data kustom ke dalam konfigurasi rute, seperti penanda bahwa rute butuh login (requiresAuth: true), level hak akses (role: 'admin'), atau judul halaman (title: 'Profil').

Konfigurasi

const routes = [
  {
    path: '/admin/settings',
    component: AdminSettingsView,
    meta: {
      requiresAuth: true,
      role: 'admin',
      title: 'Pengaturan Admin',
    },
  },
]

Membaca Meta

Meta dapat dibaca dari objek route.meta di komponen maupun di dalam Navigation Guard:

// Di Navigation Guard
router.beforeEach((to, from) => {
  if (to.meta.requiresAuth && !userIsLoggedIn()) {
    return { path: '/login' }
  }
})

Hafalan:

meta: { key: value } ──> data kustom rute untuk auth, title, atau role

17. 🟡 Navigation Guards (Proteksi Rute)

Konsep

Navigation Guards adalah mekanisme untuk mengontrol, membatasi, atau mengarahkan navigasi rute (misalnya: mencegah pengguna masuk halaman dashboard jika belum login).

Alur Urutan Eksekusi Guard

       Navigasi Dimulai (User klik link)


       1. Global Guard (router.beforeEach)


       2. Route Guard (beforeEnter di rute tujuan)


       3. In-Component Guard (onBeforeRouteUpdate / Leave)


       4. Global Resolve (router.beforeResolve)


       Navigasi Disetujui ──> Komponen Dirender


       5. Global After Hook (router.afterEach)

1. Global Before Guard (router.beforeEach)

Di Vue Router 4, gunakan nilai pengembalian (return value):

  • return false: Batalkan navigasi.
  • return { name: 'login' } atau return '/login': Alihkan ke rute lain.
  • return true atau tanpa return: Izinkan navigasi lanjut.
router.beforeEach((to, from) => {
  const isAuthenticated = checkUserToken()
 
  // Periksa apakah halaman membutuhkan autentikasi
  if (to.meta.requiresAuth && !isAuthenticated) {
    // Alihkan ke login beserta query halaman asal
    return { path: '/login', query: { redirect: to.fullPath } }
  }
})

2. Per-Route Guard (beforeEnter)

Didefinisikan langsung di dalam objek route:

{
  path: '/admin',
  component: AdminView,
  beforeEnter: (to, from) => {
    if (!isAdminUser()) return { path: '/unauthorized' }
  },
}

3. In-Component Guard (Composition API)

Vue Router menyediakan hook yang dapat dipanggil langsung di <script setup>:

<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
 
// Dipanggil saat pengguna ingin meninggalkan halaman (misal: form belum disimpan)
onBeforeRouteLeave((to, from) => {
  const answer = window.confirm('Perubahan Anda belum disimpan! Yakin ingin pergi?')
  if (!answer) return false // Batalkan navigasi
})
 
// Dipanggil saat parameter rute berubah tapi komponennya sama (misal /users/1 -> /users/2)
onBeforeRouteUpdate(async (to, from) => {
  console.log('ID Baru:', to.params.id)
})
</script>

Hafalan:

beforeEach() ──> guard global untuk seluruh rute aplikasi
return false ──> batalkan navigasi
return '/login' ──> redirect rute

18. 🟡 RouterView Slot, Transition & KeepAlive

Konsep

Di Vue 3, untuk menerapkan animasi transisi antar-halaman (<transition>) atau menyimpan cache keadaan halaman (<keep-alive>), kita wajib menggunakan sintaks Scoped Slot <RouterView v-slot="{ Component }">.

Contoh Lengkap di App.vue

<template>
  <div class="app-container">
    <Navbar />
 
    <!-- Menggunakan v-slot untuk mengakses komponen aktif -->
    <RouterView v-slot="{ Component, route }">
      <Transition name="fade" mode="out-in">
        <KeepAlive :include="['ProductListView']">
          <!-- Komponen dinamis yang dirender -->
          <component :is="Component" :key="route.path" />
        </KeepAlive>
      </Transition>
    </RouterView>
  </div>
</template>
 
<style>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
</style>

Diagram Alur Slot Rendering

       <RouterView v-slot="{ Component, route }">


             <Transition name="fade">


              <KeepAlive include="...">


            <component :is="Component" />

Hafalan:

<RouterView v-slot="{ Component }">
  <Transition>
    <KeepAlive>
      <component :is="Component" />
    </KeepAlive>
  </Transition>
</RouterView>

19. 🟡 Scroll Behavior

Konsep

Opsi scrollBehavior mengatur posisi scroll halaman secara otomatis setiap kali pengguna berpindah rute (misalnya: selalu kembali ke paling atas, atau mempertahankan posisi scroll saat menekan tombol Back browser).

Contoh Konfigurasi

const router = createRouter({
  history: createWebHistory(),
  routes,
  scrollBehavior(to, from, savedPosition) {
    // 1. Jika tombol Back/Forward browser ditekan, kembalikan ke posisi scroll sebelumnya
    if (savedPosition) {
      return savedPosition
    }
 
    // 2. Jika rute memiliki anchor hash (misal #spesifikasi), scroll ke elemen tersebut
    if (to.hash) {
      return { el: to.hash, behavior: 'smooth' }
    }
 
    // 3. Default: selalu scroll ke koordinat paling atas halaman
    return { top: 0 }
  },
})

Hafalan:

scrollBehavior: (to, from, savedPosition) => savedPosition || { top: 0 }

20. 🟡 Dynamic Routing

Konsep

Vue Router memungkinkan penambahan atau penghapusan rute secara dinamis saat aplikasi sedang berjalan (runtime). Fitur ini sangat berguna untuk aplikasi berbasis izin (RBAC), di mana menu admin baru ditambahkan ke router setelah pengguna berhasil login sebagai admin.

API Dynamic Routing

// 1. Menambahkan rute baru saat runtime
router.addRoute({
  path: '/super-admin',
  name: 'super-admin',
  component: () => import('@/views/SuperAdminView.vue'),
})
 
// 2. Menambahkan rute anak ke rute induk yang sudah ada
router.addRoute('dashboard', {
  path: 'vip',
  component: () => import('@/views/VipView.vue'),
})
 
// 3. Menghapus rute berdasarkan nama
router.removeRoute('super-admin')
 
// 4. Memeriksa keberadaan rute
router.hasRoute('super-admin') // true / false
 
// 5. Mengambil seluruh daftar rute aktif
router.getRoutes()

Hafalan:

router.addRoute(routeObj) ──> tambah rute secara dinamis saat runtime
router.removeRoute('name') ──> hapus rute dari router

21. 🔴 Navigation Failure Handling

Konsep

Navigasi programmatic (router.push) dapat dibatalkan atau dialihkan oleh Navigation Guard. Vue Router menyediakan helper untuk mendeteksi apakah navigasi sukses atau mengalami kegagalan.

Mendeteksi Kegagalan Navigasi

import { isNavigationFailure, NavigationFailureType } from 'vue-router'
 
async function navigateToAdmin() {
  const failure = await router.push('/admin')
 
  if (isNavigationFailure(failure, NavigationFailureType.aborted)) {
    console.warn('Navigasi dibatalkan oleh guard atau pengguna!')
  } else if (isNavigationFailure(failure, NavigationFailureType.redirected)) {
    console.info('Navigasi dialihkan ke rute lain oleh guard!')
  }
}

Tipe-Tipe Navigation Failure

aborted    ──> Navigasi dibatalkan (misal: return false di guard)
cancelled  ──> Navigasi baru dimulai sebelum navigasi sebelumnya selesai
redirected ──> Guard mengembalikan alamat pengalihan baru

Hafalan:

const failure = await router.push('/path')
isNavigationFailure(failure, NavigationFailureType.aborted)

22. 🧠 Peta Ingatan Cepat

A. Alur Keseluruhan Vue Router

       Klik <RouterLink> / router.push()


            Eksekusi Navigation Guard
             (beforeEach / beforeEnter)

             ┌─────────┴─────────┐
             │ Lolos             │ Batal / Redirect
             ▼                   ▼
       Router Matching     Navigasi Dialihkan


       Ekstraksi Params & Query


       Render di <RouterView />


       DOM Komponen Tampil di Layar

B. Anatomi URL & Pembacaan Data

URL: https://app.com/products/42?category=elektronik#fitur
                     │          │                    │
                     ▼          ▼                    ▼
             route.params.id  route.query.category  route.hash

C. Perbandingan useRouter vs useRoute

       ┌─────────────────────────┐     ┌─────────────────────────┐
       │       useRouter()       │     │       useRoute()        │
       ├─────────────────────────┤     ├─────────────────────────┤
       │ .push('/dashboard')     │     │ .params.id              │
       │ .replace('/login')      │     │ .query.tab              │
       │ .back() / .go(-1)       │     │ .meta.requiresAuth      │
       │ .addRoute({ ... })      │     │ .fullPath               │
       └─────────────────────────┘     └─────────────────────────┘

D. Alur Nested Routes

       /dashboard/profile


       DashboardLayout.vue (Parent)

               │ <RouterView />

       DashboardProfile.vue (Child)

23. 📚 Tabel Ringkasan

Konsep / APIFungsi UtamaContoh Sintaks
createRouter()Membuat instance router untuk aplikasi Vue 3createRouter({ history, routes })
createWebHistory()Mode HTML5 History bersih tanpa tanda pagar #history: createWebHistory()
<RouterLink>Komponen navigasi deklaratif (link internal)<RouterLink to="/about">Tentang</RouterLink>
<RouterView>Slot tempat komponen rute aktif dirender<RouterView />
useRouter()Objek pemandu untuk aksi navigasi di JavaScriptconst router = useRouter(); router.push('/home')
useRoute()Objek snapshot pembaca data URL aktif saat iniconst route = useRoute(); console.log(route.params.id)
route.paramsMengambil parameter dinamis dari URLroute.params.id
route.queryMengambil parameter query stringroute.query.search
children: []Mendefinisikan rute bertingkat (nested routes)children: [{ path: 'profile', component: Profile }]
nameMemberikan nama unik pada rute (named routes){ path: '/user/:id', name: 'user-detail' }
props: trueMengirimkan route params sebagai props komponenprops: true
() => import()Memuat komponen rute secara dinamis (lazy loading)component: () => import('@/views/About.vue')
meta: {}Menyimpan metadata kustom rutemeta: { requiresAuth: true }
beforeEach()Guard global untuk memvalidasi dan memproteksi ruterouter.beforeEach((to) => { if(!auth) return '/login' })
scrollBehaviorMengontrol posisi scroll halaman saat berpindah rutescrollBehavior(to, from, saved) { return { top: 0 } }

24. ⚡ Cheat Code Vue Router 10 Detik

createRouter()       → Membuat instance router
createWebHistory()   → Mode URL bersih tanpa #
<RouterLink to="...">→ Link pindah halaman
<RouterView />       → Tempat tampil halaman rute
useRouter()          → Pindah rute via script (router.push)
useRoute()           → Baca data rute (params, query, meta)
:param               → Parameter dinamis path
props: true          → Terima params sebagai props
children: []         → Rute bertingkat (nested route)
beforeEach()         → Guard proteksi auth rute

Contekan Cepat 1 File:

<script setup>
import { useRouter, useRoute } from 'vue-router'
 
const router = useRouter()
const route = useRoute()
 
function handleGoToDetail(id) {
  router.push({ name: 'detail', params: { id } })
}
</script>
 
<template>
  <div>
    <p>Halaman Saat Ini: {{ route.fullPath }} (ID: {{ route.params.id }})</p>
    <button @click="handleGoToDetail(99)">Buka Detail #99</button>
  </div>
</template>

25. 🧭 Urutan Belajar yang Disarankan

1. 🟢 Fundamental Routing
   ├─ Pahami konsep SPA & perbedaan link biasa vs RouterLink
   ├─ Setup createRouter() dan createWebHistory() di main.js
   ├─ Membuat routes dasar dan halaman 404 catch-all
   ├─ Membaca Route Params (:id) dan Query Params (?q=)
   └─ Menggunakan useRouter() untuk navigasi programmatic
2. 🟡 Routing Lanjutan & Tata Letak
   ├─ Menyusun Nested Routes (children) untuk dashboard bertingkat
   ├─ Menerapkan Named Routes dan Named Views
   ├─ Mengaktifkan props: true pada komponen rute
   ├─ Memahami History Modes (HTML5 vs Hash)
   └─ Mengoptimalkan performa dengan Lazy Loading (() => import())
3. 🔴 Proteksi & Animasi Rute
   ├─ Menyematkan Route Meta Fields (meta: { requiresAuth })
   ├─ Mengamankan rute dengan Navigation Guards (beforeEach)
   ├─ Membuat animasi transisi dengan RouterView Scoped Slot
   ├─ Mengatur posisi Scroll Behavior
   └─ Mengerjakan Mini Project Terpadu

26. 🏗️ Mini Project: Portal Dashboard Pengguna

Mini project ini menggabungkan: Nested Routes, Route Params, Named Routes, Props Mode, Route Meta, dan Navigation Auth Guard.

1. Konfigurasi Router (src/router/index.js)

import { createRouter, createWebHistory } from 'vue-router'
import LoginView from '@/views/LoginView.vue'
import DashboardLayout from '@/views/DashboardLayout.vue'
import UserProfile from '@/views/UserProfile.vue'
import UserPosts from '@/views/UserPosts.vue'
 
const routes = [
  {
    path: '/login',
    name: 'login',
    component: LoginView,
  },
  {
    path: '/dashboard/:id',
    name: 'dashboard',
    component: DashboardLayout,
    props: true, // id dioper sebagai props ke DashboardLayout
    meta: { requiresAuth: true },
    children: [
      {
        path: '',
        name: 'user-profile',
        component: UserProfile,
        props: true,
      },
      {
        path: 'posts',
        name: 'user-posts',
        component: UserPosts,
        props: true,
      },
    ],
  },
  {
    path: '/:pathMatch(.*)*',
    redirect: '/login',
  },
]
 
const router = createRouter({
  history: createWebHistory(),
  routes,
})
 
// Simulasi status login
const isLoggedIn = true
 
router.beforeEach((to) => {
  if (to.meta.requiresAuth && !isLoggedIn) {
    return { name: 'login' }
  }
})
 
export default router

2. Layout Induk (src/views/DashboardLayout.vue)

<script setup>
defineProps({
  id: String,
})
</script>
 
<template>
  <div class="dashboard-page">
    <header class="header">
      <h2>Portal Pengguna (ID: {{ id }})</h2>
      <nav class="nav-links">
        <RouterLink :to="{ name: 'user-profile', params: { id } }">Profil</RouterLink>
        <RouterLink :to="{ name: 'user-posts', params: { id } }">Daftar Post</RouterLink>
      </nav>
    </header>
 
    <main class="content-box">
      <!-- Area render halaman anak -->
      <RouterView />
    </main>
  </div>
</template>
 
<style scoped>
.dashboard-page { max-width: 650px; margin: 2rem auto; font-family: sans-serif; }
.header { border-bottom: 2px solid #eee; padding-bottom: 1rem; margin-bottom: 1.5rem; }
.nav-links { display: flex; gap: 1rem; margin-top: 0.5rem; }
.nav-links a { text-decoration: none; color: #333; }
.nav-links .router-link-exact-active { font-weight: bold; color: #42b883; border-bottom: 2px solid #42b883; }
.content-box { background: #fdfdfd; border: 1px solid #e2e2e2; border-radius: 8px; padding: 1.5rem; }
</style>

3. Komponen Anak (src/views/UserProfile.vue)

<script setup>
defineProps({
  id: String,
})
</script>
 
<template>
  <div>
    <h3>Informasi Profil</h3>
    <p>Selamat datang di dashboard akun #{{ id }}.</p>
  </div>
</template>

Output Tampilan Mini Project

URL: /dashboard/10
 
Portal Pengguna (ID: 10)
[ Profil ]  [ Daftar Post ]
------------------------------------------------------
Informasi Profil
Selamat datang di dashboard akun #10.
URL: /dashboard/10/posts
 
Portal Pengguna (ID: 10)
[ Profil ]  [ Daftar Post ]
------------------------------------------------------
Daftar Artikel Pengguna #10
• Belajar Vue 3 Dasar
• Panduan Vue Router 4

Diagram Alur Mini Project

       URL: /dashboard/10


       Global Guard (Cek to.meta.requiresAuth) ──> Status: LoggedIn ✓


       DashboardLayout.vue (Parent, Props id: "10")

               │ <RouterView />

       UserProfile.vue (Child Rute Aktif)

Kunci: Pahami bagaimana parameter :id mengalir dari rute induk ke rute anak, dan bagaimana meta: { requiresAuth: true } melindungi seluruh rute cabang di dalamnya.


27. 🔗 Referensi Resmi