Vue3 路由系統(Vue Router 4)——router-link 與 router-view 完全攻略
簡介
在單頁應用(SPA)中,頁面切換不再是瀏覽器的完整重新載入,而是透過路由系統在同一個 HTML 入口點內切換不同的組件。Vue3 官方配套的 Vue Router 4 提供了兩個最常使用的全域組件:router-link 與 router-view。
router-link負責宣告式的導向(導航),讓使用者點擊時能以宣告式的方式改變 URL 並觸發對應的組件渲染。router-view則是佔位符,它會根據目前的路由狀態,動態插入對應的組件。
掌握這兩個組件的使用方式與細節,才能寫出結構清晰、可維護且具備 SEO 友好(配合 SSR) 的 Vue3 應用。本篇將從概念說明、實作範例、常見陷阱與最佳實踐,一步步帶你深入了解 router-link 與 router-view 的每個細節。
核心概念
1. router-link:宣告式導航
router-link 本質上是一個 Vue 組件,它會渲染成 <a> 標籤(預設),並自動攔截點擊事件,使用 HTML5 History API(或 hash)改變瀏覽器 URL,而不會觸發頁面重新載入。
1.1 基本使用
<router-link to="/about">關於我們</router-link>
to屬性接受 字串或 路由定位物件(object),可寫成:
// 物件寫法
<router-link :to="{ name: 'User', params: { id: 123 } }">使用者 123</router-link>
1.2 常用屬性
| 屬性 | 說明 |
|---|---|
to |
目標路由(字串或物件) |
replace |
使用 router.replace(),不會留下瀏覽紀錄(預設 false) |
active-class |
當前路由匹配時套用的自訂 CSS 類名(預設 router-link-active) |
exact-active-class |
完全匹配時套用的類名(預設 router-link-exact-active) |
custom |
以「作用域插槽」的方式自行渲染 <a>,可自訂樣式或包裝元素 |
1.3 範例:自訂 active-class
<router-link to="/home" active-class="my-active">首頁</router-link>
<style>
.my-active {
color: #42b983;
font-weight: bold;
}
</style>
2. router-view:路由組件的渲染容器
router-view 只是一個 佔位符,它會根據目前的路由匹配結果,渲染對應的 路由組件。如果路由設定了巢狀子路由,則子路由的 router-view 會渲染在父組件的 router-view 內部,形成「多層嵌套」的 UI 結構。
2.1 基本使用
<!-- App.vue -->
<template>
<nav>
<router-link to="/">首頁</router-link>
<router-link to="/about">關於</router-link>
</nav>
<!-- 這裡會根據路由顯示 Home 或 About 組件 -->
<router-view />
</template>
2.2 命名視圖(Named Views)
當一個路由需要同時渲染多個視圖時,可使用 name 屬性給 router-view 命名,並在路由設定中指定 components(注意是複數)。
<!-- App.vue -->
<template>
<header>
<router-view name="header" />
</header>
<main>
<router-view />
</main>
<footer>
<router-view name="footer" />
</footer>
</template>
// router/index.js
const routes = [
{
path: '/',
components: {
default: Home, // 會渲染到未命名的 <router-view>
header: MainHeader,
footer: MainFooter
}
},
// ...
];
2.3 動態路由參數與 props 傳遞
// router/index.js
{
path: '/user/:id',
component: UserDetail,
props: true // 直接把 route.params 傳給組件的 props
}
<!-- UserDetail.vue -->
<template>
<div>使用者 ID:{{ id }}</div>
</template>
<script setup>
defineProps(['id']);
</script>
3. 程式碼範例合集
以下提供 5 個實務中常會用到的範例,從最基礎到稍微進階的情境都有涵蓋。
範例 1:基礎導航與路由設定
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '@/views/Home.vue';
import About from '@/views/About.vue';
const routes = [
{ path: '/', name: 'Home', component: Home },
{ path: '/about', name: 'About', component: About },
];
export default createRouter({
history: createWebHistory(),
routes,
});
<!-- App.vue -->
<template>
<nav>
<router-link to="/">🏠 Home</router-link>
<router-link to="/about">ℹ️ About</router-link>
</nav>
<router-view />
</template>
<script setup>
import router from '@/router';
</script>
說明:
router-link直接使用字串路徑,router-view會根據routes中的component動態渲染。
範例 2:使用路由名稱與參數
<!-- NavBar.vue -->
<template>
<router-link :to="{ name: 'User', params: { id: userId } }">
查看使用者 {{ userId }}
</router-link>
</template>
<script setup>
import { ref } from 'vue';
const userId = ref(42);
</script>
// router/index.js
{
path: '/user/:id',
name: 'User',
component: () => import('@/views/UserDetail.vue'),
props: true
}
技巧:使用路由名稱 (
name) 可以避免因路徑變更而忘記同步router-link,提升維護性。
範例 3:自訂 active-class 與 exact 匹配
<nav>
<router-link to="/" exact-active-class="active-exact">首頁</router-link>
<router-link to="/products" active-class="active">商品列表</router-link>
</nav>
<style>
.active {
color: #ff6600;
}
.active-exact {
font-weight: bold;
}
</style>
重點:
exact僅在路徑 完全相同 時才套用,適合首頁或根路由的樣式控制。
範例 4:命名視圖(Header / Footer)
<!-- Layout.vue -->
<template>
<header><router-view name="header" /></header>
<main><router-view /></main>
<footer><router-view name="footer" /></footer>
</template>
// router/index.js
{
path: '/',
components: {
default: Home,
header: MainHeader,
footer: MainFooter
}
}
實務:在大型網站(例如電商)常會把「導覽列」與「頁腳」抽成獨立元件,使用命名視圖即可在不同路由間共享或替換。
範例 5:使用 custom 插槽自行渲染連結
<router-link to="/profile" custom v-slot="{ navigate, isActive, href }">
<button :class="{ active: isActive }" @click="navigate">
個人檔案
</button>
</router-link>
<style>
button.active {
background: #42b983;
color: #fff;
}
</style>
說明:
custom讓你拋棄預設的<a>,直接用<button>、<div>或任何自訂元素,同時保留路由導航的完整功能(navigate、isActive等)。
常見陷阱與最佳實踐
| 陷阱 | 可能的結果 | 建議的解決方案 |
|---|---|---|
忘記在 router-link 加上 :to 的綁定(直接寫 to="/path") |
當路徑是變數或計算屬性時,會變成字面字串,導致導航失敗。 | 使用 :to="computedPath" 或 v-bind:to 方式綁定。 |
| 使用相對路徑時產生錯誤 | 例如在子路由中 to="detail" 會被解析成 /parent/detail,但若預期是 /detail,就會找不到組件。 |
盡量使用 絕對路徑 (/detail) 或 路由名稱 ({ name: 'Detail' })。 |
router-view 放錯位置,導致子路由渲染不到 |
子路由的內容會被渲染到父層的 router-view,或根本不顯示。 |
確認父組件中已放置 未命名的 router-view,或正確使用 name 屬性對應子路由。 |
props: true 失效 |
當組件使用 setup() 且未定義 defineProps 時,路由參數不會自動注入。 |
在 <script setup> 中使用 defineProps,或在傳統 export default 中使用 props: ['id']。 |
router-link 的 replace 誤用 |
使用 replace 後,使用者無法利用瀏覽器返回鍵回到前一頁。 |
只在「跳過歷史紀錄」的情境(如登入成功後直接導向首頁)使用。 |
最佳實踐
- 統一使用路由名稱:在大型專案中,路徑可能會因需求調整而改變,使用
name可避免每個router-link都要同步修改。 - 將路由設定拆分模組:例如
routes/auth.js、routes/dashboard.js,然後在router/index.js中匯入,提升可讀性與維護性。 - 利用
meta欄位做權限或佈局控制:在路由定義中加入meta: { requiresAuth: true, layout: 'admin' },再於全域守衛或router-view包裝層判斷。 - 懶載入(code‑splitting):使用動態匯入 (
import()) 讓每個路由只在需要時才載入,減少首屏載入大小。 - 對
router-view使用<transition>包裝:可為路由切換加入過場動畫,提升使用者體驗。
<template>
<transition name="fade" mode="out-in">
<router-view />
</transition>
</template>
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity .3s;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
</style>
實際應用場景
| 場景 | 為什麼需要 router-link / router-view |
典型實作方式 |
|---|---|---|
| 多層次管理後台 | 需要在左側選單切換不同子頁面,同時保留主內容區的切換。 | 左側選單使用 router-link(帶 active-class),右側放置 router-view,子路由再嵌套自己的 router-view。 |
| 行動端 Tab 切換 | Tab 切換本質上是路由切換,讓網址保持同步,允許深層鏈接。 | 每個 Tab 使用 router-link,router-view 放在 <keep-alive> 內部以保留狀態。 |
| 動態產品詳情頁 | 產品 ID 為路由參數,需根據 id 載入對應資料。 |
router-link 生成 /product/:id,router-view 渲染 ProductDetail.vue, props: true 直接取得 id。 |
| A/B 測試或多語系切換 | 不同語系或測試變體可能共用同一個路由,僅透過組件切換。 | 在路由的 meta 中放置語系資訊,router-view 搭配全域守衛或 watch($route) 改變組件內容。 |
| SEO 友好的 SSR | 伺服器端需要根據路由渲染完整 HTML。 | router-link 仍然產生 <a>,router-view 在服務端渲染時會輸出對應的組件 HTML。 |
總結
router-link 與 router-view 是 Vue Router 4 中最基礎、也最關鍵的兩個全域組件。透過 宣告式 的 router-link,我們可以輕鬆管理 URL 與導航行為;而 router-view 則負責根據路由狀態動態插入對應的組件,支援 命名視圖、巢狀子路由 與 懶載入 等進階功能。
在開發過程中,記得:
- 使用路由名稱 取代硬編碼路徑
- 妥善設定
active-class讓導覽列的 UI 更直觀 - 利用
props: true直接把路由參數傳給組件,減少耦合 - 善用命名視圖 讓布局層級更彈性
- 加入過場動畫 與 懶載入,提升使用者體驗與效能
只要掌握上述概念與最佳實踐,你就能在 Vue3 專案中建立結構清晰、可擴充且易於維護的路由系統,為你的 SPA 打下堅實的基礎。祝開發順利,玩得開心! 🚀