ข้ามไปยังเนื้อหา

Layouts และ Navigation

ใน React Router คุณสร้าง layout ด้วย component ที่ render <Outlet /> เพื่อให้ child routes แสดงผลตรงนั้น ส่วน Next.js App Router ใช้ไฟล์ layout.tsx ที่ wrap {children} ให้อัตโนมัติ SvelteKit ใช้แนวคิดเดียวกันผ่านไฟล์ +layout.svelte — วาง {@render children()} ไว้ตรงไหน child pages ก็จะแสดงผลตรงนั้น และ layout จะ persist ข้ามการนำทางโดยไม่ unmount

React
// src/routes/_layout.tsx (Remix) หรือ app/layout.tsx (Next.js)
export default function RootLayout({ children }) {
return (
<html>
<body>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/blog">Blog</a>
</nav>
<main>{children}</main>
</body>
</html>
);
}
Svelte
<!-- src/routes/+layout.svelte -->
<script>
let { children } = $props();
</script>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/blog">Blog</a>
</nav>
<main>
{@render children()}
</main>

จุดสำคัญ: {@render children()} ของ SvelteKit ทำหน้าที่เหมือน {children} ของ Next.js และ <Outlet /> ของ React Router — เป็นที่ที่ child page จะถูก inject เข้ามา ไฟล์ +layout.svelte ใดก็ตามที่วางอยู่ใน src/routes/ จะ wrap ทุก page ภายใต้ directory นั้น

ใน React คุณต้องใช้ <Link> component จาก react-router หรือ Next.js เพื่อ client-side navigation การใช้ <a> ธรรมดาจะทำให้ full-page reload SvelteKit จัดการสิ่งนี้ให้คุณ — ใช้ <a href> ธรรมดาได้เลย โดย SvelteKit จะ intercept การคลิกแล้วทำ client-side navigation ให้อัตโนมัติ

React
// React Router / Next.js
import { Link, useLocation } from 'react-router-dom';
// หรือ import Link from 'next/link';
// หรือ import { usePathname } from 'next/navigation';
function Nav() {
const location = useLocation();
return (
<nav>
<Link to="/" className={location.pathname === '/' ? 'active' : ''}>
Home
</Link>
<Link to="/about" className={location.pathname === '/about' ? 'active' : ''}>
About
</Link>
</nav>
);
}
Svelte
<script>
import { page } from '$app/state';
</script>
<nav>
<a href="/" class:active={page.url.pathname === '/'}>
Home
</a>
<a href="/about" class:active={page.url.pathname === '/about'}>
About
</a>
</nav>
<style>
.active { font-weight: bold; }
</style>

ไม่มี <Link> component ไม่มี useLocation hook — แค่ <a> ธรรมดาพร้อม $app/state สำหรับอ่าน URL ปัจจุบัน

page จาก $app/state คือ reactive object ที่ให้ข้อมูล route ปัจจุบัน เทียบได้กับ useLocation() + useParams() ใน React Router หรือ usePathname() + useSearchParams() ใน Next.js

<script>
import { page } from '$app/state';
</script>
<p>เส้นทางปัจจุบัน: {page.url.pathname}</p>
<p>URL params: {JSON.stringify(page.params)}</p>
<p>Search: {page.url.search}</p>

ข้อมูลสำคัญที่ page ให้:

Propertyเทียบเท่าใน React
page.url.pathnameuseLocation().pathname / usePathname()
page.paramsuseParams()
page.url.searchParamsuseSearchParams()
page.dataข้อมูลที่ load function ส่งกลับมา
page.statusHTTP status code ของหน้านี้

Layout ซ้อนกันได้ตามลำดับชั้น directory — เหมือนกับ Next.js App Router ทุกประการ

flowchart TB
  routes(["src/routes/"])
  routes --> rootLayout["+layout.svelte (root layout — nav + footer)"]
  routes --> rootPage["+page.svelte → /"]
  routes --> dashboard["dashboard/"]
  dashboard --> dashLayout["+layout.svelte (dashboard layout — sidebar)"]
  dashboard --> dashPage["+page.svelte → /dashboard"]
  dashboard --> settings["settings/"]
  settings --> settingsPage["+page.svelte → /dashboard/settings"]
Nested layouts in SvelteKit

/dashboard/settings จะได้รับทั้ง root layout และ dashboard layout ซ้อนกัน โดยไม่ต้องกำหนด config ใด ๆ เพิ่มเติม

ใน SvelteKit Svelte 5 layout child route render ที่ไหน?
คุณอ่าน pathname ปัจจุบันใน SvelteKit component ได้อย่างไร?
คุณต้องการ client-side navigation ไปหน้า /dashboard ใน SvelteKit ควรเขียนอย่างไร?