Astro - 基礎入門4.第四課練習題實作

更新 發佈閱讀 10 分鐘

題目

任務目標:建立一個動態的「隨機推薦」組件。

  1. 建立一個名為 RandomQuote.astro 的組件。
  2. 在該組件的 Code Fence 中,使用 fetch() 從 API 抓取一句隨機名言(例如:https://api.quotable.io/random)。
  3. 在 about.astro 頁面中,以 server:defer 的方式引入這個組件。
  4. 設定一個具備 Loading 樣式的 fallback 內容。
  5. 進階挑戰: 嘗試將原本的部落格清單頁面 blog.astro 改為混合模式——頁面頂部標題是靜態的,但文章清單改由 server:defer 渲染。

目前專案結構

📁 .astro/
📁 .vscode/
📁 node_modules/
📁 public/
└─ favicon.svg
📁 src/
├─ 📁 components/
│ ├─ DescriptionControl.jsx
│ ├─ LikeButton.jsx
│ └─ 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/components/RandomQuote.astro

---
let random
try {
  const res = await fetch('https://zenquotes.io/api/random')
  const data = await res.json()
  console.log(data)
  random = data
} catch (err) {
  console.error(err)
}

// 模擬一個慢速的資料庫查詢
await new Promise((resolve) => setTimeout(resolve, 2000))
---

<div class="server-box">
  <p>伺服器隨機生成:{random[0].q}</p>
  <p>(此組件是延遲載入的 Server Island)</p>
</div>

<style>
  .server-box {
    border: 2px dashed #ff5d01;
    padding: 1rem;
    background: #fff5f0;
  }
</style>

2_修改 src/pages/about.astro

  1. 匯入 RandomQuote 物件
  2. html 區塊找一個地方放 RandomQuote
  3. <p> 沒有加 slot="fallback" 是不會顯示的喔
---
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>
</BaseLayout>

3_進階挑戰

3_1 新增 src/components/PostsQuote.astro

---
import { getCollection } from 'astro:content'
import type { CollectionEntry } from 'astro:content'
const posts: CollectionEntry<'blog'>[] = await getCollection('blog')
// 模擬資料庫查詢
await new Promise((resolve) => setTimeout(resolve, 2000))
---

<ul>
  {
    posts
      .sort((a, b) => {
        const a_date = a.data.pubDate.toDateString()
        const b_date = b.data.pubDate.toDateString()
        return b_date.localeCompare(a_date)
      })
      .map((post) => (
        <li>
          <a href={`/posts/${post.id}`}>{post.data.title}</a>
          <span> - {post.data.pubDate.toLocaleDateString()} </span>
        </li>
      ))
  }
</ul>

3_2 修改 src/pages/blog.astro

---

// import { getCollection } from 'astro:content'
// import type { CollectionEntry } from 'astro:content'
import BaseLayout from '../layouts/BaseLayout.astro'
import PostsQuote from '../components/PostsQuote.astro'
const pageTitle = '我的部落格'
// const allPosts: CollectionEntry<'blog'>[] = await getCollection('blog')
---

<BaseLayout pageTitle={pageTitle}>
  <PostsQuote server:defer>
    <p slot="fallback" class="loading">文章列表載入中...</p>
  </PostsQuote>
  <!-- <ul>
    {
      allPosts
        .sort((a, b) => {
          const b_date = b.data.pubDate.toDateString()
          const a_date = a.data.pubDate.toDateString()
          return b_date.localeCompare(a_date)
        })
        .map((post) => (
          <li>
            <a href={`/posts/${post.id}`}>{post.data.title}</a>
            <span> - {post.data.pubDate.toLocaleDateString()} </span>
          </li>
        ))
    }
  </ul> -->
</BaseLayout>
留言
avatar-img
李昀瑾的沙龍
0會員
37內容數
李昀瑾的沙龍的其他內容
2026/01/11
第四課:Server Islands 與 SSR (伺服器端渲染) 在之前的課程中,我們的網站是「靜態」的。 但在真實應用中,有些內容不能是靜態的(例如:用戶登入狀態、即時庫存、或是根據地理位置推薦的內容)。 1. 核心觀念:Server Islands vs. Client Islands
2026/01/11
第四課:Server Islands 與 SSR (伺服器端渲染) 在之前的課程中,我們的網站是「靜態」的。 但在真實應用中,有些內容不能是靜態的(例如:用戶登入狀態、即時庫存、或是根據地理位置推薦的內容)。 1. 核心觀念:Server Islands vs. Client Islands
2026/01/10
第三課:Astro Islands —— 混合開發與互動性 核心觀念:預設 0 JS Astro 就像一個「大洋」,預設所有組件都是靜態的 HTML(沒有 JS)。如果你需要互動(如:彈窗、購物車、即時搜尋),你就在大洋中丟入一個「孤島 (Island)」。
2026/01/10
第三課:Astro Islands —— 混合開發與互動性 核心觀念:預設 0 JS Astro 就像一個「大洋」,預設所有組件都是靜態的 HTML(沒有 JS)。如果你需要互動(如:彈窗、購物車、即時搜尋),你就在大洋中丟入一個「孤島 (Island)」。
2026/01/10
Astro - 基礎入門3.第三課練習題實作
2026/01/10
Astro - 基礎入門3.第三課練習題實作
看更多
你可能也想看
Thumbnail
網站開發專案成功的關鍵在於與客戶的有效溝通。本文分享一個成功案例,說明如何透過明確掌握專案需求、主動提供技術方案、定期回報進度、完善技術協助及建立良好客戶關係,順利完成一個中文影片學習分享網站的建置,並獲得客戶高度滿意與後續合作機會。
Thumbnail
網站開發專案成功的關鍵在於與客戶的有效溝通。本文分享一個成功案例,說明如何透過明確掌握專案需求、主動提供技術方案、定期回報進度、完善技術協助及建立良好客戶關係,順利完成一個中文影片學習分享網站的建置,並獲得客戶高度滿意與後續合作機會。
Thumbnail
從實際應用中學習 Python 程式設計,提升技能並建立作品集。文章提供八個循序漸進的 Python 專案範例,涵蓋檔案操作、網路爬蟲、Web 應用、自動化腳本、數據分析、遊戲開發、API 互動及應用程式部署,並附上實戰建議及學習資源。
Thumbnail
從實際應用中學習 Python 程式設計,提升技能並建立作品集。文章提供八個循序漸進的 Python 專案範例,涵蓋檔案操作、網路爬蟲、Web 應用、自動化腳本、數據分析、遊戲開發、API 互動及應用程式部署,並附上實戰建議及學習資源。
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
這是一場從「網路連結 → 線下見面」的活動,我一開始其實有些猶豫,畢竟地點對我來說不近,加上平常在社群裡其實不太主動互動。 但因為主辦人西打誠意滿滿地邀請,甚至還提出補貼車資,最後我決定自費參加。現在回頭看,真的很值得! 場地很有感,氛圍超溫暖 一踏進場地就被暖黃的燈光包圍,小閣樓超舒適,還
Thumbnail
這是一場從「網路連結 → 線下見面」的活動,我一開始其實有些猶豫,畢竟地點對我來說不近,加上平常在社群裡其實不太主動互動。 但因為主辦人西打誠意滿滿地邀請,甚至還提出補貼車資,最後我決定自費參加。現在回頭看,真的很值得! 場地很有感,氛圍超溫暖 一踏進場地就被暖黃的燈光包圍,小閣樓超舒適,還
Thumbnail
Nuxt.js 是以 Vue 為基底所建構的框架,透過 Nuxt.js,我們能夠更輕鬆地開發靜態頁面 (Static Site)、操作體驗良好的單頁式網站 (SPA)、甚至是顧及 SEO 的伺服器端渲染 (SSR) 網站。
Thumbnail
Nuxt.js 是以 Vue 為基底所建構的框架,透過 Nuxt.js,我們能夠更輕鬆地開發靜態頁面 (Static Site)、操作體驗良好的單頁式網站 (SPA)、甚至是顧及 SEO 的伺服器端渲染 (SSR) 網站。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News