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 也会以这个例子出发,敬请期待!

延伸阅读