模板表達式參考
Astro 元件語法是 HTML 的超集合,寫過 HTML 或 JSX 的人會感到熟悉,而且它還支援匯入元件與 JavaScript 表達式。
類 JSX 表達式
標題為 類 JSX 表達式你可以在 Astro 元件內兩道圍欄(---
)中的 frontmatter 元件腳本定義本地 JavaScript 變數,接著使用類 JSX 表達式將這些變數注入到元件的 HTML 模板!
透過這種方式,frontmatter 可以計算並包含動態值。一旦包含其中,這些值便不再是互動式,之後也無法改變。Astro 元件這種模板只會在算繪階段執行一次而已。
詳見:Astro 和 JSX 的差異。
變數
標題為 變數本地變數可以透過大括弧(curly braces)加入 HTML:
---const name = "Astro";---<div> <h1>Hello {name}!</h1> <!-- 會輸入成 <h1>Hello Astro!</h1> --></div>
動態屬性
標題為 動態屬性本地變數也能透過大括弧傳遞屬性值給 HTML 元素與元件:
---const name = "Astro";---<h1 class={name}>支援屬性表達式</h1>
<MyComponent templateLiteralNameAttribute={`MyNameIs${name}`} />
HTML 屬性會轉換成字串,因此無法傳遞函式和物件給 HTML 元素。 舉例來說,在 Astro 元件裡,你不能指派 event handler 給 HTML 元素:
---function handleClick () { console.log("button clicked!");}---<!-- ❌ 無法這麼做!❌ --><button onClick={handleClick}>點選這個按鈕,什麼事也不會發生!</button>
正確的做法是透過客戶端 JavaScript 建立 event handler,如同原生 JavaScript 寫法:
------<button id="button">點選這個按鈕</button><script> function handleClick () { console.log("button clicked!"); } document.getElementById("button").addEventListener("click", handleClick);</script>
動態 HTML
標題為 動態 HTML類 JSX 函式可以使用本地變數動態產生 HTML 元素:
---const items = ["Dog", "Cat", "Platypus"];---<ul> {items.map((item) => ( <li>{item}</li> ))}</ul>
使用 JSX 邏輯運算子和三元表達式,Astro 能依照條件顯示 HTML。
---const visible = true;---{visible && <p>Show me!</p>}
{visible ? <p>Show me!</p> : <p>Else show me!</p>}
動態標籤
標題為 動態標籤把 HTML 標籤名稱指派給變數,或將匯入的元件再次指派,便可使用動態標籤:
---import MyComponent from "./MyComponent.astro";const Element = 'div'const Component = MyComponent;---<Element>Hello!</Element> <!-- 算繪成 <div>Hello!</div> --><Component /> <!-- 算繪成 <MyComponent /> -->
使用動態標籤時:
-
變數名稱首字要大寫。舉例來說:使用
Element
而不是element
。否則,Astro 會嘗試將變數名稱算繪成一般的 HTML 標籤。 -
不支援水合作用指令(hydration directive)。使用
client:*
水合作用指令 (EN)時,Astro 需要事先知道哪個元件會被打包進正式版本,因此這種情況下不適用動態標籤。 -
不支援 define:vars 指令 (EN)。如果不能為子元素包上額外的元素(例如
<div>
),你可以手動在元素加上style={`--myVar:${value}`}
。
Fragment
標題為 FragmentAstro 支援 <> </>
表示法,也有提供內建的 <Fragment />
元件。有了它,在使用 set:*
指令 (EN) 時便不需要額外包一層元素。
下面的範例用了 <Fragment />
元件算繪出一段文字:
---const htmlString = '<p>原始 HTML 內容</p>';---<Fragment set:html={htmlString} />
Astro 和 JSX 的差異
標題為 Astro 和 JSX 的差異Astro 元件語法是 HTML 的超集合,寫過 HTML 或 JSX 的人會感到熟悉。但 .astro
檔案和 JSX 仍有些關鍵差異。
屬性
標題為 屬性所有屬性在 Astro 都用標準的 kebab-case
格式,而 JSX 則使用 camelCase
。class
對 Astro 來說也一樣,然而 React 卻不支援這點。
<div className="box" dataValue="3" /><div class="box" data-value="3" />
複數元素
標題為 複數元素與 JavaScript 或 JSX 不同,Astro 元件模板能算繪多個元素,不需要額外包一層 <div>
或 <>
。
---// 有多個元素的模板---<p>不需要用容器把多個元素包起來。</p><p>Astro 模板支援複數根元素。</p>
註解
標題為 註解在 Astro 可以使用標準的 HTML 註解或 JavaScript 風格的註解。
------<!-- HTML 註解語法在 .astro 檔案是合法的 -->{/* JS 註解語法也同樣合法 */}
HTML 風格的註解會出現在瀏覽器的 DOM,而 JS 風格的註解則不會。如果需要留下待辦註解或其他開發用的訊息,建議使用 JavaScript 風格的註解。
元件工具
標題為 元件工具Astro.slots
標題為 Astro.slotsAstro.slots
有幾個工具函式可以用來修改 Astro 元件由插槽傳入的子元素。
Astro.slots.has()
標題為 Astro.slots.has()型別:(slotName: string) => boolean
你可以用 Astro.slots.has()
確認特定插槽名稱的內容是否存在。這在你想包裹插槽內容,但只想在插槽被使用時才算繪包裹元素的時候很好用。
------<slot />
{Astro.slots.has('more') && ( <aside> <h2>更多</h2> <slot name="more" /> </aside>)}
Astro.slots.render()
標題為 Astro.slots.render()型別:(slotName: string, args?: any[]) => Promise<string>
你可以用 Astro.slots.render()
非同步算繪插槽內容成 HTML 字串。
---const html = await Astro.slots.render('default');---<Fragment set:html={html} />
這是給進階的使用案例用的!在大多數情況下,用 <slot />
元素算繪插槽內容比較簡單。
Astro.slots.render()
可以接受第二個引數:會轉傳到任何子元素函式的參數陣列。這對於自訂工具元件來說很有用。
舉例來說,這個 <Shout />
元件將它的 message
參數轉換成大寫,傳遞到預設的插槽:
---const message = Astro.props.message.toUpperCase();let html = '';if (Astro.slots.has('default')) { html = await Astro.slots.render('default', [message]);}---<Fragment set:html={html} />
做為 <Shout />
的子元素傳遞的回呼函式會收到全部大寫的 message
參數:
---import Shout from "../components/Shout.astro";---<Shout message="slots!"> {(message) => <div>{message}</div>}</Shout>
<!-- 會算繪成 <div>SLOTS!</div> -->
回呼函式可以傳遞到被有 slot
屬性的 HTML 元素標籤包著的具名插槽。這個元素只用來將回呼函式傳遞到具名插槽,並不會算繪到頁面上。
<Shout message="slots!"> <fragment slot="message"> {(message) => <div>{message}</div>} </fragment></Shout>
請使用標準的 HTML 元素或不會被解釋為元件的任何小寫標籤(例如 <fragment>
而不是 <Fragment />
)來當做包裹標籤。不要用 HTML <slot>
元素,因為會被解釋為 Astro 插槽。
Astro.self
標題為 Astro.selfAstro.self
讓 Astro 元件能被遞迴呼叫。這個行為讓你用元件模板內的 <Astro.self>
從 Astro 元件內算繪它自己。這對於遍歷大量資料儲存和巢狀資料結構有幫助。
---const { items } = Astro.props;---<ul class="nested-list"> {items.map((item) => ( <li> <!-- 如果有巢狀資料結構就算繪 `<Astro.self>` --> <!-- 還可以由遞迴呼叫傳遞參數過去 --> {Array.isArray(item) ? ( <Astro.self items={item} /> ) : ( item )} </li> ))}</ul>
可以像這樣使用這個元件:
---import NestedList from './NestedList.astro';---<NestedList items={['A', ['B', 'C'], 'D']} />
算繪出的 HTML 會像這樣:
<ul class="nested-list"> <li>A</li> <li> <ul class="nested-list"> <li>B</li> <li>C</li> </ul> </li> <li>D</li></ul>