Next.js 路由系統 (App Router)
Next.js 的路由系統是建立在「檔案架構」之上的。在 App Router 模式中,目錄的層級直接映射到 URL 的路徑。這種設計非常直觀,讓你一眼就能看出網站的地圖。
基礎路由定義
在 app 資料夾中,每個資料夾代表一個 路由分段 (Route Segment),而路徑則是從根目錄開始累積的。
- 要讓一個路徑可以被存取,該資料夾下必須包含一個
page.tsx。
範例:
| URL 路徑 | 檔案路徑 |
|---|---|
/ | app/page.tsx |
/about | app/about/page.tsx |
/blog/first-post | app/blog/first-post/page.tsx |
// app/about/page.tsx
export default function AboutPage() {
return <h1>關於我們</h1>;
}
巢狀路由 (Nested Routes)
你可以隨意深度的巢狀資料夾來建立複雜的路徑。
例如一個電商網站的分類頁面:
app/shop/electronics/page.tsx 會對應到 /shop/electronics。
路由預讀 (Prefetching)
Next.js 有一個非常迷人的功能:自動預讀 (Automatic Prefetching)。
當一個 <Link> 元件出現在使用者的視窗中(Viewport)時,Next.js 會在背景自動下載該路由的程式碼和初始內容。
- 這意味著當使用者點擊連結時,跳轉幾乎是瞬發的,因為內容已經存在於快取中。
Link 元件用法:
import Link from 'next/link';
export default function Navigation() {
return (
<nav>
<Link href="/">首頁</Link>
<Link href="/about">關於</Link>
{/* 你可以手動關閉預讀 */}
<Link href="/heavy-page" prefetch={false}>
負載較重的頁面
</Link>
</nav>
);
}
路由群組 (Route Groups)
有時候你希望把資料夾組織起來,但不希望這些資料夾的名稱出現在 URL 路徑中。這時可以使用括號 (folderName) 來建立路由群組。
路由群組的主要用途有兩個:開發者專案組織與佈局共享隔離。
邏輯組織 (Project Organization)
當你的專案變大時,可以利用群組將相關的路由放在一起,而不影響 URL。例如將所有身分驗證相關的頁面歸類在 (auth) 資料夾:
app/(auth)/login/page.tsx→ URL 是/loginapp/(auth)/register/page.tsx→ URL 是/register
這樣在檔案管理上會非常整潔,但對使用者來說 URL 依然簡短。
不同區域共享不同 Layout
這是 Route Groups 最強大的地方。你可以為特定的群組定義專屬的 layout.tsx,而不會影響到其他群組。
例如,你希望「行銷頁面」有導覽列,但「後台管理」需要側邊攔:
app/
├── (marketing)/
│ ├── layout.tsx // 包含 Navigation & Footer
│ ├── about/
│ │ └── page.tsx // URL: /about (套用行銷 Layout)
│ └── page.tsx // URL: / (套用行銷 Layout)
└── (dashboard)/
├── layout.tsx // 包含 Sidebar & Admin Header
└── settings/
└── page.tsx // URL: /settings (套用管理 Layout)
建立多重根佈局 (Multiple Root Layouts)
如果你想讓網站的各個部分擁有完全不同的外觀(例如 <html> 和 <body> 標籤都不同),你可以刪除最外層的 app/layout.tsx,並在每個路由群組中各放一個。
私有資料夾 (Private Folders)
如果你想在路由目錄下放置組件或測試檔案,但不想讓它變成路徑,可以使用底線前綴 _folderName。
app/_components/Button.tsx:這不會變成路徑,即使裡面有page.tsx也會被忽略。
編程導航 (Programmatic Navigation)
除了 <Link>,有時你需要在程式邏輯中切換路由(例如登入成功後跳轉)。這時可以使用 useRouter 鉤子。
useRouter 必須在 Client Component 中使用。'use client';
import { useRouter } from 'next/navigation';
export default function LoginForm() {
const router = useRouter();
const handleLogin = () => {
// 執行登入邏輯...
router.push('/dashboard');
};
return <button onClick={handleLogin}>登入</button>;
}
理解了基礎路由後,我們接下來要討論如何讓這些頁面共享共同的結構,也就是 Layouts。