面向 WordPress 開發者的 Astro

本頁內容

Astro 為 EmDash 網站提供頁面、佈局、元件和伺服器渲染。本指南涵蓋當前 EmDash 範本使用的 Astro 概念。假設你已經了解 WordPress 佈景主題和 PHP 範本。

對於非 EmDash 特有的框架功能,請使用 Astro 文件

專案結構

Astro 網站為每種檔案類型分配一個明確的目錄。當前的 EmDash 範本使用以下結構:

WordPressAstro用途
index.phpsingle.phppage.phpsrc/pages/URL 路由
template-parts/src/components/可重複使用的標記
header.phpfooter.phpsrc/layouts/共用頁面外殼
style.csssrc/styles/網站樣式
外掛和資料庫設定astro.config.mjs整合和伺服器轉接器
佈景主題設定資料seed/seed.json集合、選單和範例內容

部落格範本使用與其公開 URL 相符的路由目錄:

src/
├── components/
│   └── PostCard.astro
├── layouts/
│   └── Base.astro
├── pages/
│   ├── index.astro
│   ├── pages/
│   │   └── [slug].astro
│   └── posts/
│       ├── index.astro
│       └── [slug].astro
└── live.config.ts

Astro 元件

.astro 元件結合了伺服器端 TypeScript 和 HTML 範本。--- 圍欄之間的程式碼在伺服器上執行。第二個圍欄下方的標記成為回應 HTML。

以下元件在其 frontmatter 中宣告 props,並在範本中渲染它們:

---
interface Props {
  title: string;
  excerpt?: string;
  href: string;
}

const { title, excerpt, href } = Astro.props;
---

<article>
  <h2><a href={href}>{title}</a></h2>
  {excerpt && <p>{excerpt}</p>}
</article>

Astro 會對使用 {value} 渲染的值進行跳脫。匯入、資料庫查詢和其他伺服器操作屬於 frontmatter。

範本表達式

Astro 範本在 PHP 範本會切換到 <?php ?> 的位置使用大括號。EmDash 範本中最常見的模式是值、條件和陣列映射:

目的Astro 語法
輸出值{post.data.title}
值存在時渲染{post.data.excerpt && <p>{post.data.excerpt}</p>}
在兩個結果間選擇{posts.length === 0 ? <p>尚無文章。</p> : <PostList />}
渲染清單{posts.map((post) => <PostCard title={post.data.title} excerpt={post.data.excerpt} href={"/posts/" + post.id} />)}

表達式可以使用 frontmatter 中準備的變數、Astro.props 中的值或 EmDash 查詢返回的資料。Astro 預設會跳脫字串值;使用 <PortableText /> 等渲染器來處理結構化富文本,而不是注入 HTML。

Props 和插槽

Props 類似於傳遞給 get_template_part()$args。它們使每個輸入明確,並可以由 TypeScript 進行檢查。

插槽允許父元件向子元件傳遞標記。預設插槽適用於頁面內容,而具名插槽提供額外的插入點:

---
interface Props {
  title: string;
}

const { title } = Astro.props;
---

<article>
  <h2>{title}</h2>
  <slot />
  <footer><slot name="footer" /></footer>
</article>

以下頁面填充了兩個插槽:

---
import Card from "../components/Card.astro";
---

<Card title="最新文章">
  <p>卡片的主要內容。</p>
  <a slot="footer" href="/posts/latest">閱讀文章</a>
</Card>

插槽對於元件呼叫是局部的。它們不像 WordPress 的 action 那樣可以接收在其他地方註冊的回呼。

佈局

佈局擁有 WordPress 佈景主題通常在 header.phpfooter.php 之間分割的共用文件結構。頁面匯入佈局並透過其插槽傳遞內容。

以下佈局提供了一個文件外殼:

---
interface Props {
  title: string;
}

const { title } = Astro.props;
---

<!doctype html>
<html lang="zh-TW">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>{title}</title>
  </head>
  <body>
    <header><a href="/">我的網站</a></header>
    <main><slot /></main>
  </body>
</html>

以下頁面提供佈局的標題和主要內容:

---
import Base from "../layouts/Base.astro";
---

<Base title="首頁">
  <h1>最新文章</h1>
</Base>

基於檔案的路由

src/pages/ 中的檔案定義路由。方括號檔名建立動態區段。

檔案URL
src/pages/index.astro/
src/pages/posts/index.astro/posts
src/pages/posts/[slug].astro/posts/hello-world
src/pages/pages/[slug].astro/pages/about

src/pages/posts/[slug].astro 內部,Astro.params.slug 包含 URL 中的值。有關剩餘參數、重新導向和其他路由功能,請閱讀 Astro 路由

伺服器渲染

當前的 EmDash 範本在 astro.config.mjs 中使用 output: "server"。因此頁面可以在每次請求時查詢資料庫,已發布的內容不依賴於新的靜態建置。

除非網站刻意將 EmDash 作為建置時資料來源,否則不要向 EmDash 佈景主題路由新增 getStaticPaths()。提供的佈景主題是伺服器渲染的。

有關框架級行為,請閱讀 Astro 隨選渲染

查詢 EmDash 內容

EmDash 使用 getEmDashCollection()getEmDashEntry() 包裝 Astro 即時內容集合。集合結果包含一個 entries 陣列。單一項目結果包含 entry,當沒有已發布的項目匹配時為 null

以下封存使用與當前部落格範本相同的排序和識別碼:

---
import { getEmDashCollection } from "emdash";
import Base from "../../layouts/Base.astro";

const { entries: posts, error } = await getEmDashCollection("posts", {
  orderBy: { published_at: "desc" },
});

if (error) {
  return new Response("無法載入文章", { status: 500 });
}
---

<Base title="文章">
  {posts.map((post) => (
    <article>
      <h2><a href={`/posts/${post.id}`}>{post.data.title}</a></h2>
      {post.data.excerpt && <p>{post.data.excerpt}</p>}
    </article>
  ))}
</Base>

post.id 是 Astro 公開的路由識別碼,通常是項目的 slug。post.data.id 是資料庫識別碼。當 API 期望儲存的內容 ID 時(如分類法或留言輔助函式),請使用 data.id

以下動態路由按 URL 中的 slug 尋找文章並渲染其 Portable Text 欄位:

---
import { decodeSlug, getEmDashEntry } from "emdash";
import { PortableText } from "emdash/ui";
import Base from "../../layouts/Base.astro";

const slug = decodeSlug(Astro.params.slug);
if (!slug) return Astro.redirect("/404");

const { entry: post, error } = await getEmDashEntry("posts", slug);
if (error) return new Response("無法載入文章", { status: 500 });
if (!post) return Astro.redirect("/404");
---

<Base title={post.data.title}>
  <article>
    <h1>{post.data.title}</h1>
    <PortableText value={post.data.content} />
  </article>
</Base>

繼續學習 Astro

EmDash 範本還使用元件樣式和小型瀏覽器指令碼,但這些是普通的 Astro 功能而非 EmDash 概念。有關範圍和全域樣式,請閱讀樣式和 CSS;當元件需要瀏覽器端行為時,請閱讀指令碼和事件處理