跳到內容

模板表達式參考

Astro 元件語法是 HTML 的超集合,寫過 HTML 或 JSX 的人會感到熟悉,而且它還支援匯入元件與 JavaScript 表達式。

你可以在 Astro 元件內兩道圍欄(---)中的 frontmatter 元件腳本定義本地 JavaScript 變數,接著使用類 JSX 表達式將這些變數注入到元件的 HTML 模板!

本地變數可以透過大括弧(curly braces)加入 HTML:

src/components/Variables.astro
---
const name = "Astro";
---
<div>
<h1>Hello {name}!</h1> <!-- 會輸入成 <h1>Hello Astro!</h1> -->
</div>

本地變數也能透過大括弧傳遞屬性值給 HTML 元素與元件:

src/components/DynamicAttributes.astro
---
const name = "Astro";
---
<h1 class={name}>支援屬性表達式</h1>
<MyComponent templateLiteralNameAttribute={`MyNameIs${name}`} />

類 JSX 函式可以使用本地變數動態產生 HTML 元素:

src/components/DynamicHtml.astro
---
const items = ["Dog", "Cat", "Platypus"];
---
<ul>
{items.map((item) => (
<li>{item}</li>
))}
</ul>

使用 JSX 邏輯運算子和三元表達式,Astro 能依照條件顯示 HTML。

src/components/ConditionalHtml.astro
---
const visible = true;
---
{visible && <p>Show me!</p>}
{visible ? <p>Show me!</p> : <p>Else show me!</p>}

把 HTML 標籤名稱指派給變數,或將匯入的元件再次指派,便可使用動態標籤:

src/components/DynamicTags.astro
---
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}`}

Astro 支援 <> </> 表示法,也有提供內建的 <Fragment /> 元件。有了它,在使用 set:* 指令 (EN) 時便不需要額外包一層元素。

下面的範例用了 <Fragment /> 元件算繪出一段文字:

src/components/SetHtml.astro
---
const htmlString = '<p>原始 HTML 內容</p>';
---
<Fragment set:html={htmlString} />

Astro 和 JSX 的差異

標題為 Astro 和 JSX 的差異

Astro 元件語法是 HTML 的超集合,寫過 HTML 或 JSX 的人會感到熟悉。但 .astro 檔案和 JSX 仍有些關鍵差異。

所有屬性在 Astro 都用標準的 kebab-case 格式,而 JSX 則使用 camelCaseclass 對 Astro 來說也一樣,然而 React 卻不支援這點。

example.astro
<div className="box" dataValue="3" />
<div class="box" data-value="3" />

與 JavaScript 或 JSX 不同,Astro 元件模板能算繪多個元素,不需要額外包一層 <div><>

src/components/RootElements.astro
---
// 有多個元素的模板
---
<p>不需要用容器把多個元素包起來。</p>
<p>Astro 模板支援複數根元素。</p>

在 Astro 可以使用標準的 HTML 註解或 JavaScript 風格的註解。

example.astro
---
---
<!-- HTML 註解語法在 .astro 檔案是合法的 -->
{/* JS 註解語法也同樣合法 */}

Astro.slots 有幾個工具函式可以用來修改 Astro 元件由插槽傳入的子元素。

型別:(slotName: string) => boolean

你可以用 Astro.slots.has() 確認特定插槽名稱的內容是否存在。這在你想包裹插槽內容,但只想在插槽被使用時才算繪包裹元素的時候很好用。

src/pages/index.astro
---
---
<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} />

Astro.slots.render() 可以接受第二個引數:會轉傳到任何子元素函式的參數陣列。這對於自訂工具元件來說很有用。

舉例來說,這個 <Shout /> 元件將它的 message 參數轉換成大寫,傳遞到預設的插槽:

src/components/Shout.astro
---
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 參數:

src/pages/index.astro
---
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 元件能被遞迴呼叫。這個行為讓你用元件模板內的 <Astro.self> 從 Astro 元件內算繪它自己。這對於遍歷大量資料儲存和巢狀資料結構有幫助。

NestedList.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>
貢獻 社群 贊助