Astro - 基礎入門5.第五課練習題實作

更新 發佈閱讀 10 分鐘

題目

任務目標:實作一個「留言板」功能。

  1. 在 src/actions/index.ts 中,增加一個新的 Action 叫做 postComment
  2. 這個 Action 需要接收 author (字串) 和 content (字串)。
  3. 在 handler 中,將收到的資料 console.log 出來(模擬存入資料庫),並回傳「留言成功」。
  4. 在 about.astro 建立一個簡單的表單,讓使用者輸入名字與內容,並在提交後用 alert() 顯示伺服器的回傳訊息。
  5. 進階挑戰: 嘗試在 Action 的 input 中使用 z.string().min(5),看看如果你輸入少於 5 個字的內容,前端會收到什麼樣的錯誤訊息?

目前專案結構

📁 .astro/
📁 .vscode/
📁 node_modules/
📁 public/
└─ favicon.svg
📁 src/
├─ 📁 actions/
│ └─ index.ts
├─ 📁 components/
│ ├─ DescriptionControl.jsx
│ ├─ LikeButton.jsx
│ ├─ PostsQuote.astro
│ ├─ RandomQuote.astro
│ └─ ServerTime.astro
├─ 📁 content/
│ ├─ 📁 blog/
│ │ └─ post-1.md
│ └─ config.ts
├─ 📁 layouts/
│ └─ BaseLayout.astro
└─ 📁 pages/
├─ 📁 posts/
│ └─ [id].astro
├─ about.astro
├─ blog.astro
└─ index.astro
.gitignore
astro.config.mjs
package-lock.json
package.json
README.md
tscon

1_修改 src/actions/index.ts

import { defineAction } from "astro:actions";
import { z } from "astro:schema";

export const server = {
  getGreeting: defineAction({
    input: z.object({
      name: z.string()
    }),
    handler: async (input) => {
      return `你好 ${input.name},這是來自伺服器的回覆!`;
    }
  }),

  postComment: defineAction({
    input: z.object({
      author: z.string(),
      content: z.string(),
    }),
    handler: async (input) => {
      console.log(input);
      return "留言成功";
    }
  }),
}

2_修改 src/pages/about.astro

---
import BaseLayout from '../layouts/BaseLayout.astro'
import DescriptionControl from '../components/DescriptionControl'
import RandomQuote from '../components/RandomQuote.astro'
const pageTitle = '關於我'
const identity = {
  firstName: '小明',
  hobbies: ['reading', 'gaming', 'coding'],
}
const description =
  '這段文字旨在模擬實際使用中的描述欄位,長度超過二十個字以符合需求。'
---

<BaseLayout pageTitle={pageTitle} pageName="about">
  <h2>{identity.firstName}</h2>

  <h3>我的愛好</h3>

  <ul>
    {identity.hobbies.map((x) => <li>{x}</li>)}
  </ul>

  <h3>描述</h3>
  <DescriptionControl description={description} client:visible />

  <h3>隨機生成</h3>
  <RandomQuote server:defer>
    <p slot="fallback" class="loading">等待隨機生成....</p>
  </RandomQuote>

  <form id="form">

    <input
      type="text"
      name="author"
      id="author"
      placeholder="使用者名稱"
      required="required"
    />

    <input
      type="text"
      name="content"
      id="content"
      placeholder="輸入留言"
      required="required"
    />
    <button type="submit">發送</button>
  </form>

  <script>
    import { actions } from 'astro:actions'
    const formElement = document.querySelector('form')

    formElement?.addEventListener('submit', async (e) => {
      e.preventDefault()
      const formData = new FormData(formElement)
      const author = formData.get('author') as string
      const content = formData.get('content') as string

      const { data, error } = await actions.postComment({ author, content })
      if (!error) {
        alert(data)
      } else {
        alert(error)
      }
    })
  </script>
</BaseLayout>

3_進階挑戰

3.1_修改 src/actions/index.ts

import { defineAction } from "astro:actions";
import { z } from "astro:schema";

export const server = {
  getGreeting: defineAction({
    input: z.object({
      name: z.string()
    }),
    handler: async (input) => {
      return `你好 ${input.name},這是來自伺服器的回覆!`;
    }
  }),

  postComment: defineAction({
    input: z.object({
      author: z.string(),
      content: z.string().min(5), // 修改這裡
    }),
    handler: async (input) => {
      console.log(input);
      return "留言成功";
    }
  }),
}
留言
avatar-img
李昀瑾的沙龍
0會員
25內容數
李昀瑾的沙龍的其他內容
2026/01/12
第五課:Astro Actions —— 安全、簡單的伺服器通訊 核心觀念:Actions 是什麼? 前你需要寫一個 src/pages/api/login.ts,然後在前端寫 fetch('/api/login', { method: 'POST', ... })。 在 Astro 5 中,
Thumbnail
2026/01/12
第五課:Astro Actions —— 安全、簡單的伺服器通訊 核心觀念:Actions 是什麼? 前你需要寫一個 src/pages/api/login.ts,然後在前端寫 fetch('/api/login', { method: 'POST', ... })。 在 Astro 5 中,
Thumbnail
2026/01/11
Astro - 基礎入門4.第四課練習題實作
2026/01/11
Astro - 基礎入門4.第四課練習題實作
2026/01/11
第四課:Server Islands 與 SSR (伺服器端渲染) 在之前的課程中,我們的網站是「靜態」的。 但在真實應用中,有些內容不能是靜態的(例如:用戶登入狀態、即時庫存、或是根據地理位置推薦的內容)。 1. 核心觀念:Server Islands vs. Client Islands
2026/01/11
第四課:Server Islands 與 SSR (伺服器端渲染) 在之前的課程中,我們的網站是「靜態」的。 但在真實應用中,有些內容不能是靜態的(例如:用戶登入狀態、即時庫存、或是根據地理位置推薦的內容)。 1. 核心觀念:Server Islands vs. Client Islands
看更多