Skip to content
這是本書第一版(1/e)的封存內容,僅供查閱、不再更新。最新內容請見 最新版。

v-conf Taiwan 2026:連結社群,啟發未來

4-1 Vue Router 與前後端路由 ​

如同前面章節介紹過的,Vue.js 的核心是用來處理「狀態」與「網頁模板」的映射關係。 當整個網站逐漸發展成為應用程式的時候,Vue.js 元件、甚至是頁面之間切換的流程、狀態的邏輯, 若要使用原本我們所熟悉的 v-if 、 :is 指令,就顯得有些力不從心。

而本章所要介紹的 Vue Router ,作為 Vue.js 框架生態圈的一部分,彌補了 Vue.js 核心薄弱的部分, 除了前面提到控制元件的切換邏輯之外,還能搭配前端路由機制來操作瀏覽器上/下一頁的流程, 這使得 Vue.js 也有了能夠建立 SPA 完整單頁式應用的能力。

多頁式應用 (MPA) 與 單頁式應用 (SPA) ​

最早期的網頁幾乎都是以靜態網頁為主,所有資料直接從 Server 端輸出,幾乎不需要做運算,HTML 內容就是單純的文字、圖片等靜態資料,頁面之間各自是獨立的狀態。 後來過了幾年,有了「動態網頁程式」的語言 (如 PHP、ASP 等) 才開始由後端程式語言負責處理頁面邏輯,加上資料庫系統的成熟,使得原本無法紀錄狀態的網頁,可以利用資料庫來記錄狀態及資料。人們這才開始意會到,原來網頁是可以用來開發「應用程式」的。

當網頁逐漸往應用程式發展之後,網站的架構就從原本的「靜態網頁」變成了「動態網頁」,那麼,什麼是動態網頁呢?

假設我們要做一個電商網站,最基本可能就會有「商品列表頁」、「商品說明頁」、「購物車頁」、「結帳頁」... 等類型。 其他的先不說,就拿「商品說明頁」來做例子。

以傳統的 「靜態網頁」 來說,一個商品就會有一個屬於自己的獨立「商品說明頁」,那假如網站上面有一百個商品, 網站的開發者就得分別維護這一百個 「商品說明頁」,即便他們的結構是一樣的,只是內容不同。

而轉換成動態網頁,由於主要是搭配伺服器與資料庫共同運作,網頁的內容會隨著使用者的操作和互動而有所不同, 於是原本一百個靜態的 「商品說明頁」,其實我們只需要一頁商品說明頁的「結構」,再搭配伺服器端與資料庫渲染出不同的內容即可。

什麼是路由 ​

那麼,網站的伺服器怎麼知道什麼時候要提供什麼資料給使用者呢? 熟悉網站操作的各位一定知道,就是透過網址的結構。

sh
│
├── 商品列表 /products-list
│   ├── 商品分類 /category-1
│   │   ├── 商品頁  /category-1/product-1
│   │   ├── 商品頁  /category-1/product-2
│   │   └── ... 
│   │
│   └── 商品分類 /category-2
│       ├── 商品頁  /category-2/product-1
│       ├── 商品頁  /category-2/product-2
│       └── ... 
│
├── 首頁 /home
├── 關於我們 /about
├── 購物車 /cart
└── ...

舉例來說,上面這是個很常見的網站結構,我們可以透過網誌 https://xxx.xxx/products-list 來進入商品列表頁,甚至再往下一層還有 https://xxx.xxx/category-1 與 https://xxx.xxx/category-1/product-1 進入分類頁以及商品的說明頁。

像這樣,瀏覽器透過不同的網址,向後端的網頁伺服器發送請求 (Request),而伺服器接收到瀏覽器的請求後, 回應對應的內容給瀏覽器來渲染,這樣的機制我們就稱為網站路由 (Routing) ,管理網站路由的程式通常會被稱作 Router。

網站路由

後端路由 vs 前端路由 ​

前面介紹的是傳統後端路由的概念。

而隨著時間發展,前端在整個網頁領域的比例越來越吃重,尤其是自 Ajax 技術問世之後,省下了換頁的成本, 透過 JavaScript 將網頁的內容替換,使用者與網頁畫面的互動不需要重新載入網頁,操作的回饋也更即時。

但同時也遇到了新的挑戰,更新後的內容在網頁重新整理後沒辦法被留存。

過去使用者的習慣,回到前一個步驟通常會去按「上一頁」,但網頁是由 Ajax 更新的資料,根本沒有「換頁」這個行為, 哪裡來的上一頁與下一頁可以給使用者切換。

幸好後來 HTML5 新的規範提供了 History API,可以透過 pushState 、 replaceState 來更新 URL, 同時也提供了 state 物件讓開發者存取網頁的狀態,這就使 JavaScript 開始獲得控制路由的權利。

前端路由

需要注意的是,若要將網站原本後端伺服器控制路由改為前端接手時, 需要改寫原本的後端路由規則,將所有網址都指向 Vue.js 的單一入口。

以 Vue.js 的好朋友 Laravel 為例,首先要將所有的入口都指向同一個頁面,再由這頁去渲染 Vue.js:

php
// routes/web.php
Route::get('/{any}', 'SinglePageController@index')->where('any', '.*');

接著,在 SinglePageController 將 index 指向 app:

php
class SinglePageController extends Controller
{
  public function index()
  {
    return view('app');
  }
}

最後記得在 /resources/views/app.blade.php 新增 <div id="app">...</div> 以及 <script src="{{ mix('js/app.js') }}"></script> 將 Vue.js 以及前端程式的進入點引入到網頁上。

php
// resources/views/app.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vue SPA Demo</title>
</head>
<body>
  <div id="app">
    <app></app>
  </div>

  <script src="{{ mix('js/app.js') }}"></script>
</body>
</html>

如此一來,不管瀏覽器從哪個 URL 進入,都能確保看到的是 index 的頁面,此時,就輪到 Vue.js 與 Vue Router 的前端路由來接手畫面的渲染了。

前端路由

小提醒

除了上述的 Laravel 之外,其他後端程式語言也可利用類似做法,如 Rails 可以透過 Rails.application.routes 來指定後端路由、ASP.NET Core 也能透過 routes.MapRoute 來設定路由等。

Vue Router 介紹 ​

瞭解了後端路由與前端路由的差別後,接著要來介紹本章的主角「Vue Router」。

Vue Router 是 Vue.js 官方提供的前端路由管理器,截至目前 (2020-12-27) 的最新版本為 v4.0.2。 由於 Vue 3.0 開始使用 createApp 建立元件實體,所以 Vue Router v3 以前的版本將無法支援 Vue 3.0。

注意 - Vue Router 版本選擇

為配合 Vue 3.x 的內容,本書所採用的是 Vue Router v4.x (https://next.router.vuejs.org/),若讀者使用的是 Vue 2.x 版本,請務必選用 Vue Router v3.x (https://router.vuejs.org/),而兩個版本間使用的 API 也有些許不同。

注意,由於 Vue 3.0 底層核心改寫,所以 Vue Router v3.x 無法相容 Vue.js 3.0

若想知道 Vue Router 新舊版本差異,可以參考 https://next.router.vuejs.org/guide/migration/index.html 一頁。

Vue Router 安裝 ​

安裝 Vue Router 的方式非常簡單。

如果是新建立的專案,可以利用前一章所介紹的 Vue CLI 建立專案,並選取 Router 選項:

sh
? Check the features needed for your project:
(Press <space> to select, <a> to toggle all, <i> to invert selection)

❯◉ Choose Vue version
 ◉ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
 ◉ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◯ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

因為我們選了安裝 Router,所以接下來 Vue CLI 會問你是否採用 history mode,這裏我們先選 Y, 表示採用 HTML5 的 history API 來管理前端路由:

sh
? Use history mode for router? 
(Requires proper server setup for index fallback in production) (Y/n)

其他部分則是與前面介紹過的一樣。


另外,如果是已經建立好的專案,但在專案建置時並未安裝過 Vue Router 也不用擔心, 只需要打開終端機並切換到專案目錄下,執行:

sh
# 有安裝 Vue CLI 的情況
$ vue add router@next

接著同樣會詢問你使否採用 history mode:

sh
? Use history mode for router? 
(Requires proper server setup for index fallback in production) (Y/n)

然後讓它跑一會,就安裝完成了。


若讀者朋友並未安裝 Vue CLI,也可透過 npm 或 yarn 來進行安裝:

sh
$ npm install vue-router@4
# 或者 yarn add vue-router@4

採用 CDN 方式的讀者也可以直接在網頁引入 <script> 標籤:

html
<scripr src="https://unpkg.com/vue-router@4"></script>

這樣就可以了。

Vue Router 的第一步 ​

安裝了 Vue Router 之後,接著我們需要在網頁加入 <router-view> 來當作 Route 的進入點, 並且使用 <router-link> 來產生對應的連結:

html
<div id="app">
  <h1>Hello Vue Router App!</h1>

  <p>
    <!-- router-link 在經過編譯後會變成 <a> 標籤 -->
    <!-- 使用 to 屬性來處理目標 URL -->
    <router-link to="/">Go to Home</router-link>
    <router-link to="/about">Go to About</router-link>
  </p>

  <!-- 渲染 route 的位置 -->
  <router-view></router-view>
</div>
js
// 定義兩個 route 元件,分別是 Home 與 About
const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }

// 指定 URL 與對應的元件
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
]

// 建立 VueRouter 實體物件
const router = VueRouter.createRouter({
  history: VueRouter.createWebHistory(),
  routes: routes,
});

// 建立 Vue 實體元件
const app = Vue.createApp({});

// 透過 app.use(router) 使 app 的所有子元件
// 都能存取 this.$router 與 this.$route
app.use(router);

// 掛載 Vue.js 實體至 DOM
app.mount('#app');

如果是使用 Vue CLI 的讀者,可自行修改 (或新增) route.js 檔案,使用方式大致上於前面相同, 差別只在 routes 元件可以是某個 .vue 檔案,並將其透過 import 的方式引入進來:

js
// route.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'

export const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', component: Home },
    { path: '/about', component: About },
  ],
});

接著在 main.js 透過 .use(router) 加入至 app:

js
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import { route } from './route';

const app = createApp(App).use(route);
app.mount('#app');

像這樣,渲染在網頁上的結果,就會出現 「Go to Home」 與 「Go to About」 兩個連結, 當點擊其中一個連結之後,畫面並不會被轉導到另一個網頁,而是將對應的元件渲染在 <router-view></router-view> 的區塊當中。

試一試

雖然只是很單純的元件切換,到目前為止我們已經成功使用 Vue Router 建立了一個基本的單頁式應用,那麼在後續的章節中,將為讀者們介紹更多 Vue Router 的相關細節與設定。