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

Layouts

ใน Next.js App Router คุณสร้าง layout.tsx ไว้ข้างๆ หน้าและ React จะครอบ children ด้วย layout นั้นโดยอัตโนมัติ ใน Astro ไม่มีการครอบ layout อัตโนมัติ — คุณสร้าง layout component ใน src/layouts/ และ import ใช้อย่างชัดเจน ภายในแต่ละหน้า layout รับเนื้อหาของหน้าผ่าน <slot /> ซึ่งเทียบเท่ากับ children prop ของ React

Layout ต้องการ project หลายไฟล์เพื่อสังเกตผล — รัน example เหล่านี้ใน Astro project เต็มรูปแบบ (npm create astro@latest) ในเครื่องของคุณ

Next.js
// app/layout.tsx (Next.js App Router)
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<head>
<title>My Site</title>
</head>
<body>
<nav>My Nav</nav>
<main>{children}</main>
<footer>My Footer</footer>
</body>
</html>
);
}
Astro
---
// src/layouts/Layout.astro
interface Props {
title?: string;
}
const { title = 'My Site' } = Astro.props;
---
<html lang="en">
<head>
<meta charset="utf-8" />
<title>{title}</title>
</head>
<body>
<nav>My Nav</nav>
<main>
<slot /> <!-- เนื้อหาของหน้าจะแสดงที่นี่ -->
</main>
<footer>My Footer</footer>
</body>
</html>
Next.js
// app/about/page.tsx (Next.js App Router)
// layout.tsx ครอบโดยอัตโนมัติ — ไม่ต้อง import
export default function AboutPage() {
return <h1>About</h1>;
}
// -----------------------------------------
// pages/_app.tsx (Next.js Pages Router)
// import type { AppProps } from 'next/app';
// export default function App({ Component, pageProps }: AppProps) {
// return <Layout><Component {...pageProps} /></Layout>;
// }
Astro
---
// src/pages/about.astro
// Layout ต้อง import อย่างชัดเจนในทุกหน้า
import Layout from '../layouts/Layout.astro';
---
<Layout title="About">
<h1>About</h1>
<p>Welcome to the about page.</p>
</Layout>

Astro รองรับ named slot สำหรับการฉีดเนื้อหาเข้าไปยังพื้นที่เฉพาะของ layout — คล้ายกับ named children pattern ใน React (ใช้ render prop หรือ portal) แต่ built into ภาษา

React
// React named-area pattern (render props)
function Layout({ nav, main }: {
nav: React.ReactNode;
main: React.ReactNode;
}) {
return (
<div>
<aside>{nav}</aside>
<main>{main}</main>
</div>
);
}
// Usage
<Layout
nav={<NavLinks />}
main={<ArticleContent />}
/>
Astro
---
// src/layouts/TwoColumn.astro
---
<div>
<aside>
<slot name="sidebar" /> <!-- named slot -->
</aside>
<main>
<slot /> <!-- default slot -->
</main>
</div>
<!-- การใช้ในหน้า -->
---
import TwoColumn from '../layouts/TwoColumn.astro';
---
<TwoColumn>
<nav slot="sidebar">
<a href="/a">Link A</a>
</nav>
<article>เนื้อหาหลักที่นี่</article>
</TwoColumn>
flowchart TD
  src["src/"] --> layouts["layouts/"]
  src --> pages["pages/"]
  layouts --> layout["Layout.astro (base HTML shell: head, nav, footer)"]
  layouts --> blogLayout["BlogLayout.astro (extends Layout, adds sidebar)"]
  pages --> index["index.astro imports Layout from '../layouts/Layout.astro'"]
  pages --> about["about.astro imports Layout from '../layouts/Layout.astro'"]
  pages --> blog["blog/"]
  blog --> slug["[slug].astro imports BlogLayout from '../../layouts/BlogLayout.astro'"]
Layouts and pages file tree
element ใดของ Astro ที่เทียบเท่ากับ `children` prop ของ React ภายใน layout?
Astro ใช้ layout กับหน้าอย่างไร เมื่อเทียบกับ Next.js App Router?
ตำแหน่งที่นิยมใช้วาง layout component ใน Astro project คือที่ใด?