前面除了創建新專案之外也了解了 Astro CLI 與設定檔的大致樣貌,本章節會從創建基本 Astro 元件開始,元件可以被放置在先前提到的 src
資料夾當中,建議創建一個 components
資料夾存放在內以方便管理。
可以藉由創建一個副檔名為 .astro
的檔案來撰寫 Astro 元件,元件中分為腳本與模板兩個區塊,這兩個區塊由柵欄(---
)所區隔。
---
// 元件腳本
---
<!-- 元件模板 -->
元件腳本代表該元件在伺服端中會被如何執行,像是你可以在這裡撰寫 JavaScript 或 TypeScript 用於:
---
// 1. 導入 Astro 元件
import SomeAstroComponent from './components/SomeAstroComponent.astro';
// 2. 引入不同框架的元件
import SomeReactComponent from './components/SomeReactComponent.jsx';
// 3. 引入資料
import pokemons from '../data/pokemon.json';
// 3. 引入資料
const user = await fetch('SOME_SECRET_API_URL/users').then(r => r.json());
// 4. 透過解構獲得該元件所接收到的 props
const { title } = Astro.props;
const message = 'Astro is Awesome!'
---
<!-- 5. 創建變數並在元件模板中存取 -->
I think: { message }
{ title }
關於第 5 點,可以在伺服端 JavaScript 中創建變數使用 {}
單括弧插入到模板中,不管是屬性還是作為 Props 傳入:
---
import Modal from './components/Modal.astro'
const message = 'Hello Astro'
---
<Modal class={message} message={`${message} Here Is My Props`} />
或者是撰寫 JavaScript 表達式來產生 HTML,就像是 JSX 一樣:
---
const fruits = ['Apple', 'Banana', 'Cherry']
---
<ul>
{fruits.map(fruit => <li>{fruit}<li>)}
</ul>
或是選擇性的顯示模板內容:
---
const isOnSale = true
---
{isOnSale && <p>正在打折中!</p>}
{isOnSale ? <p>正在打折中!</p> : <p>尚無打折</p>}
或是動態的決定標籤種類(須留意動態標籤不支援 Hydration、並且標籤命名必須大寫,才能分辨出是原生標籤還是客製化元件):
---
import MyComponent from "./MyComponent.astro";
const Element = 'div'
const Component = MyComponent;
---
<Element>Hello!</Element> <!-- 渲染出 <div>Hello!</div> -->
<Component /> <!-- 渲染出 <MyComponent /> -->
可以設定讓元件接受外部傳入的屬性,只需要在元件內的伺服端腳本中從 Astro.props
中來獲得,像以下的例子 greeting
與 name
兩個變數被使用解構的方式創建出來:
---
// 元件外: <GreetingHeadline greeting="Hi" name="Joe" />
const { greeting, name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>
甚至可以為 Props 添加型別,讓文字編輯器可以知道「該元件應該要傳入什麼類型的東西」:
interface Props {
greeting: string;
name: string;
}
除了元件屬性也可以透過插槽的方式將外部的 HTML 內容傳入到元件之中,舉例來說:由於目前網站大多數頁面都包含了導覽列與頁腳元件,於是你可以創建一個名為 Base
的元件作為網頁的通用元件。
---
import Navbar from '../components/Navbar.astro'
import Hero from '../components/Hero.astro'
import Footer from '../components/Footer.astro'
---
<Navbar />
<Hero />
<slot />
<Footer />
並且在每個頁面中引入該元件,不但可以統一管理所有頁面的架構,也不用在每一頁反覆的引入基本需要的元件。
---
import Base from '../layouts/Base.astro
---
<Base>
<!-- 此區間的模板將注入 slot 中 -->
</Base>
可以擁有一個以上的插槽,這時候使用具名插槽來指定「要注入內容的插槽」。舉例來說根據先前的範例:
<Navbar />
<slot name="before-hero" />
<Hero />
<slot />
<Footer />
就可以使用 slot
屬性來指定想注入的插槽名稱。
<Base>
<!-- 以下圖片將會注入到 before-hero 插槽中 -->
<img src ="example.jpg" slot="before-hero">
<!-- 以下沒有特別註明 slot 將注入到預設 slot 中 -->
<h1>你好世界</h1>
</Base>
當在定義插槽的位址時,可以為其添加內容,這些內容就會成為當沒有任何模板傳遞進來時所採用的預設內容。
<slot>
<p>這是預設後備方案,當沒有模板傳遞到 slot 時就會被採用</p>
</slot>
插槽可以被轉移到其他的元件之中,舉例來說有個元件: BaseLayout.astro
---
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<slot name="head"/>
</head>
<body>
<slot />
</body>
</html>
而它被 HomeLayout.astro
所引用:
---
import BaseLayout from "./BaseLayout.astro";
---
<BaseLayout>
<slot name="head" slot="head"/>
<slot />
</BaseLayout>
這時候再對 HomeLayout.astro
傳入 head
插槽將會轉移到 BaseLayout
的 head
插槽之中。
---
import HomeLayout from "../layouts/HomeLayout.astro";
---
<HomeLayout>
<title slot="head">Astro</title>
<h1>Astro</h1>
</HomeLayout>
如果你先前有接觸過其他框架或 JSX 就會發現這些「元件」間的觀念都很雷同好上手,並且由於 .astro
設計主要用於伺服器渲染,因此不用擔心狀態反應性的問題,極大的刪減了複雜度!
最後會建議實際動手練習,如果過程中有問題可以參考看看我的範例:
components
資料夾內撰寫像是 Navbar
、 Footer
之類常見的元件。pages
資料夾內的頁面中導入並顯示你新製作好的元件。layouts
資料夾內創建一個名為 Base
的元件,並且透過 <slot />
讓整個網站的頁面都使用該元件,甚至更進一步接受 Props 讓該元件提供更多彈性可被修改的空間(像是接受修改 <head>
中的 meta
標籤們)。(目前 iT 邦不支援 Astro 語法的高光😅,因此歡迎到我的部落格閱讀本系列相關文章,正同步更新中!)