Day7 - Astro Series: Build a button component

Astro 系列文第七日:實作按鈕元件

一個漂亮的漸層背景上面有一句標題:「實作按鈕元件」

前言

前面學習了如何撰寫元件並添加樣式,具備了基礎撰寫元件的能力,接下來兩個章節都會打鐵趁熱來製作一個實際且極具代表性的元件 —— 「按鈕」。

定義問題

網站中要用到許多種類的按鈕,但每個按鈕都創立一個元件又難以管理,像是: <a> 按鈕、 <button> 按鈕……而按鈕的樣式更是千變萬化,像是:實心、外框、幽靈、底線連結、資訊、警告、危險、成功……如果每個按鈕都寫個元件也太累人了吧!於是希望能夠運用先前所學,撰寫一個「通用按鈕元件」,並且藉由傳入元件的 Props 來創建對應按鈕元件 —— 「 Button.astro」。

第一步:定義 Props

首先這個按鈕將會接收按鈕連結、樣式、大小等自訂的 Props,並且使用其餘參數將任何剩餘的 Props 給解構出來並放到標籤上:

---
const {href, theme, size, ...rest } = Astro.props
---
<a href={href} {...rest}>
<slot/>
</a>

第二步:動態決定標籤

由於並不是任何按鈕都有連結,因此可以透過動態標籤來決定標籤的種類,如果存在 href 便是 <a> 標籤,反之則是 <button> 標籤:

---
const {href, theme, size, ...rest } = Astro.props
const Element = href ? 'a' : 'button'
---
<Element href={href} {...rest}>
<slot/>
</Element>

第三步:添加按鈕樣式

預設將會套用 btn 樣式並且依照傳入的內容來決定按鈕風格與尺寸的樣式:

---
const {href, theme, size, ...rest } = Astro.props
const Element = href ? 'a' : 'button'
const themeClass = theme ? `btn--${theme}` : 'btn--primary'
const sizeClass = size ? `btn--${size}` : 'btn--md'
---
<Element href={href} class:list={['btn', themeClass, sizeClass]} {...rest}>
<slot/>
</Element>

接著只需要撰寫對應的按鈕風格即可:

<style>
/* 自行編寫樣式 */
.btn {}
.btn:hover {}
.btn--primary {}
.btn--secondary {}
.btn--sm {}
.btn--md {}
.btn--lg {}
</style>

這樣 Button.astro 超級按鈕就完成了!輸入對應的 Props 與 Slot,該元件就會產生出對應種類的按鈕。

額外步驟:添加 Type

最後再為元件的 Props 添加 TypeScript。

interface Props {
href?: string;
size?: "sm" | "md" | "lg";
theme?:
| "primary"
| "secondary"
}

至於標籤的型別實作我想與 Polymorphic type🔗 有關,但我暫且看不懂這個 helper 的用法 😅,如果你知道的話歡迎發言分享。

總結

在本章節綜合了先前「基礎元件」與「樣式」兩章節的內容,打造出一個通用的網頁按鈕元件,一起來實作看看吧。按鈕是網頁極具代表性的元件之一,下一章節講解整合 Tailwind 也會以這個例子出發,敬請期待!

延伸閱讀