Vue Router 基本安裝與設定
簡介
在單頁應用 (SPA) 中,路由是負責在不同畫面之間切換的核心機制。Vue 3 搭配官方的 Vue Router 4,提供了直觀且功能完整的路由解決方案。無論是簡單的靜態頁面切換,或是需要權限守衛、懶載入、動態路由參數的複雜需求,都能在 Vue Router 中得到支援。
本篇文章將從 安裝、基本設定、常見用法 逐步說明,讓剛接觸 Vue 3 的開發者能快速上手,並在實務專案中正確運用路由系統。
核心概念
1. Vue Router 的組件結構
Vue Router 主要由三個概念組成:
| 概念 | 說明 |
|---|---|
| Router | 整個路由器實例,負責管理路由表、導航守衛等。 |
| Route Record | 路由記錄,也就是在 routes 陣列中定義的每一條路由規則。 |
| Router View / Router Link | Vue 提供的兩個組件:<router-view> 用於顯示對應的組件,<router-link> 用於產生可點擊的導航連結。 |
Tip:在 Vue 3 中,
createRouter與createWebHistory(或createWebHashHistory)是建立 Router 時最常使用的兩個函式。
2. 安裝 Vue Router
在使用 Vue CLI、Vite 或 Nuxt 時,都可以透過 npm 或 yarn 安裝套件。以下以 Vite 為例:
npm install vue-router@4
# 或者使用 yarn
yarn add vue-router@4
注意:Vue Router 4 只能與 Vue 3 搭配使用,若仍在使用 Vue 2,請改用 Vue Router 3。
3. 建立路由表
路由表是一個描述「網址 ↔️ 組件」對應關係的陣列。最簡單的範例如下:
// 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: '/', // URL 路徑
name: 'home', // 命名路由(可選)
component: HomeView // 對應的 Vue 組件
},
{
path: '/about',
name: 'about',
component: AboutView
}
]
// 建立 router 實例
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), // 使用 HTML5 History 模式
routes // 上方宣告的路由表
})
export default router
4. 在根實例中掛載 Router
在 main.js(或 main.ts)中,把剛剛建立的 router 注入 Vue 應用:
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 匯入 router
const app = createApp(App)
// 使用 router
app.use(router)
// 掛載根組件
app.mount('#app')
5. 使用 <router-view> 與 <router-link>
在 App.vue 中,<router-view> 會根據目前的路由顯示對應的子組件,而 <router-link> 則是產生可點擊的連結。
<!-- src/App.vue -->
<template>
<nav>
<!-- 使用 router-link 產生導向連結 -->
<router-link to="/">首頁</router-link>
<router-link to="/about">關於我們</router-link>
</nav>
<!-- 依路由顯示對應組件 -->
<router-view />
</template>
<style scoped>
nav {
padding: 1rem;
background-color: #f5f5f5;
}
router-link {
margin-right: 1rem;
text-decoration: none;
color: #333;
}
router-link-active {
font-weight: bold;
}
</style>
6. 懶載入 (Code‑Splitting)
在大型專案中,直接把所有組件一次載入會造成首屏載入時間過長。Vue Router 支援 動態匯入,讓每條路由在需要時才載入對應的組件。
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
name: 'home',
component: () => import('@/views/HomeView.vue') // ← 懶載入
},
{
path: '/about',
name: 'about',
component: () => import('@/views/AboutView.vue')
},
{
path: '/user/:id',
name: 'user',
// 透過路由參數傳遞 ID,組件同樣使用懶載入
component: () => import('@/views/UserDetail.vue')
}
]
export default createRouter({
history: createWebHistory(),
routes
})
7. 動態路由參數與 Props
有時候需要把 URL 中的參數直接傳給組件作為 props,這樣可以避免在組件內部使用 $route.params。
// src/router/index.js
{
path: '/product/:pid',
name: 'product',
component: () => import('@/views/ProductDetail.vue'),
props: true // 讓 pid 直接成為組件的 prop
}
<!-- src/views/ProductDetail.vue -->
<template>
<div>
<h2>商品編號:{{ pid }}</h2>
<!-- 之後可以根據 pid 再去呼叫 API 取得商品資料 -->
</div>
</template>
<script setup>
defineProps({
pid: {
type: String,
required: true
}
})
</script>
8. 導航守衛 (Navigation Guards)
導航守衛可以在路由切換前、切換後或錯誤時執行自訂邏輯,常見用途包括 驗證使用者是否已登入、紀錄頁面停留時間 等。
(1) 全局前置守衛
// src/router/index.js
router.beforeEach((to, from, next) => {
const isLoggedIn = Boolean(localStorage.getItem('token'))
// 假設所有以 /admin 開頭的路由都需要驗證
if (to.path.startsWith('/admin') && !isLoggedIn) {
// 未登入則導回首頁
next({ name: 'home' })
} else {
// 繼續導航
next()
}
})
(2) 單一路由的守衛
// 只在進入 /profile 時檢查權限
{
path: '/profile',
name: 'profile',
component: () => import('@/views/Profile.vue'),
beforeEnter: (to, from, next) => {
const hasPermission = /* 你的權限判斷邏輯 */
if (hasPermission) next()
else next({ name: 'home' })
}
}
(3) 組件內部守衛
// src/views/Settings.vue
<script>
export default {
// 當路由對應到此組件時會先執行
beforeRouteEnter(to, from, next) {
console.log('即將進入 Settings')
next()
},
// 當路由離開此組件時會執行
beforeRouteLeave(to, from, next) {
if (confirm('確定離開此頁面嗎?')) {
next()
} else {
next(false) // 取消離開
}
}
}
</script>
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方式 |
|---|---|---|
| 忘記掛載 router | 在 main.js 中未呼叫 app.use(router),導致 <router-view> 永遠不會渲染。 |
確認 router 已正確注入根實例。 |
| 路由路徑與組件檔名不一致 | 路徑寫錯或大小寫不符,會產生 404 錯誤。 | 使用 IDE 的自動補全或在路由表中統一管理。 |
懶載入未使用 webpackChunkName |
打包後產生過多小檔案,影響效能。 | 可在 import() 中加入 /* webpackChunkName: "chunk-name" */ 註解(Vite 可自行分割)。 |
全局守衛內部未呼叫 next() |
導航會停在當前畫面,造成卡住的感覺。 | 在所有分支路徑都必須呼叫 next() 或回傳 false。 |
| 路由參數類型錯誤 | 例如把數字參數傳給字串型別的 props。 |
在 defineProps 中明確宣告類型,或在守衛中做型別轉換。 |
最佳實踐
- 使用命名路由:
name屬性可以讓你在程式碼中引用路由時更具可讀性,且不受 URL 改變影響。 - 路由懶載入 + 佈局 (Layout) 結構:將共同的 UI(如側邊欄、導航列)抽成 Layout 組件,子路由只負責主要內容,提高可維護性。
- 統一管理路由常數:將路由名稱、路徑抽成
constants/router.js,避免硬編碼。 - 在守衛內部使用 async/await:如果需要呼叫 API 判斷權限,使用
async函式,並在next()前完成所有非同步工作。 - 設定
scrollBehavior:讓使用者在返回上一頁時自動回到原本的捲動位置,提升使用體驗。
// src/router/index.js
export default createRouter({
history: createWebHistory(),
routes,
scrollBehavior(to, from, savedPosition) {
// 若有保存的捲動位置則返回該位置
if (savedPosition) {
return savedPosition
} else {
// 否則回到頁面頂端
return { top: 0 }
}
}
})
實際應用場景
| 場景 | 需求 | Vue Router 解法 |
|---|---|---|
| 企業內部系統 | 多層級權限、子路由、動態載入 | 使用嵌套路由 (children) 搭配全局守衛驗證權限,懶載入各功能模組。 |
| 電商網站 | 商品列表、商品詳情、搜尋參數保留 | 使用路由參數 (/product/:id) 以及 query string (/search?keyword=手機) 讓 SEO 友好且可直接分享。 |
| 部落格 | 文章分頁、標籤過濾、文章預覽 | 透過 props: true 把 page、tag 直接傳給列表組件,並在 beforeRouteUpdate 中偵測參數變化重新抓資料。 |
| 行動 App (使用 Capacitor) | 需要支援離線瀏覽、深層連結 | 使用 createWebHashHistory 或 createMemoryHistory(在原生容器中)避免瀏覽器 History 失效。 |
| 多語系網站 | 路徑依語系變化 (/en/home, /zh-tw/home) |
在路由表的 path 前加上語系參數,或使用全局導航守衛自動切換 locale。 |
總結
Vue Router 4 為 Vue 3 提供了 直觀、彈性又功能完整 的路由解決方案。從 安裝、建立路由表、掛載至根實例,到 懶載入、動態參數、導航守衛,每一步都能讓開發者以最少的程式碼實現強大的頁面切換與權限控制。
在實務開發中,記得:
- 命名路由 讓程式更易讀;
- 懶載入 減少首屏載入時間;
- 導航守衛 為安全與使用者體驗提供保障;
- 統一管理路由常數、設定 scrollBehavior 等細節,能讓專案更具可維護性。
透過本文的範例與最佳實踐,你已具備在 Vue 3 專案中建立、設定與最佳化路由的能力。接下來,只要結合 Vuex/Pinia、Composition API 等其他生態系統工具,就能打造出 完整、流暢且具擴充性的單頁應用。祝開發順利,玩得開心!