沒想到拆元件居然真的講了三天。在實作的時候常常會感覺跳過很多步驟,但實際上沒有跳,只是每個步驟都做得好快,有些甚至可以一起進行,也就是說,只要熟練了之後,就會忘記當初不熟的時候有多麼卡住...今天在做的時候,又想起了一些可能該知道的事情,就在這篇文章跟大家分享看看吧。
元件都是用大寫來作為開頭,資料夾名稱則是都用小寫,算是一種取名字慣例,一開始我在寫程式的時候,也不知道為什麼要這樣做,後來才發現這樣做其實有一些方便的地方。
其實,全部都用 div 也能把版切好。
當堆疊了太多的標籤,鑲嵌的又太深的時候,常常會很混亂,所以跟大家分享我自己使用語意化標籤的方法。
<section>
用在 Page 的最外層,與 <div>
形成區別<ul>
與 <li>
代表有序的清單,我通常會在 Menu 或者有相關的元件集合裡面去用它<dl>
也是清單,但與上一位不同的是,它的子元件有 <dt>
跟 <dd>
,前者代表一個標題,後者就沒有標題的意思<time>
這樣的標籤,而且這個標籤是真的有,就只是用來告訴大家裡面包的是時間製作了 TodoPage 跟 DashboardPage 之後,對於 HomePage 有了點新的靈感。
所以修改了原本畫過的 Function Map,加上了快速新增一則 todo 的區塊,而且因為 DashboardPage 設計出來了,所以覺得可以將各個櫃子概略的狀態放上來,就能一目了然。
接下來我要使用 modal 彈跳視窗的方式,來做新增 todo 的 UI。
我很討厭 modal,從我在純切版,手刻 RWD 的時期就已經是這樣,手刻得出來,但就是很煩。
後來我習慣用一個套件來幫助我做 modal,就是 Reach UI 裡面的 Dialog(Modal),嘗試了很多個最後用的最順手的就是它了。
因為很多 UI 庫都會有 Modal 可以用,只要用自己喜歡的那個就行了。
跟著官方文件來安裝,總之用自己順手的套件管理工具 :
npm install @reach/dialog
# or
yarn add @reach/dialog
引入 :
import { Dialog, DialogOverlay, DialogContent } from "@reach/dialog";
import "@reach/dialog/styles.css";
接下來會用到表單樣式,但 tailwind 原來是不能動表單樣式的,這個時候我們需要安裝一個 tailwind plugin,@tailwindcss/forms。
安裝 @tailwindcss/forms 到專案裡面 :
npm install -D @tailwindcss/forms
然後到 tailwind.config.js 把它掛上去 :
// tailwind.config.js
module.exports = {
theme: {
// ...
},
plugins: [
require("@tailwindcss/forms"),
// ...
],
};
以上都安裝完畢,要再專案裡面使用 modal 囉。
首先,在 components 資料新增 Modal.tsx :
import { Dialog } from "@reach/dialog";
import "@reach/dialog/styles.css";
const Modal = ({ children, isOpen }) => {
return (
<Dialog className="w-[40%]" isOpen={isOpen}>
{children}
</Dialog>
);
};
export default Modal;
再回到要使用 modal 的頁面,也就是 TodoPage,把 Modal 引入之後,再已經切好的表單放進去,因為切版已經做過了,所以我就不再贅述:
...
<Modal isOpen={isOpen}>
<div className="flex justify-end">
<span
className="
font-medium
cursor-pointer
inline-block
bg-gray-200
w-[24px] text-center rounded"
onClick={() => setIsOpen(false)}
>
X
</span>
</div>
<div className="py-12 flex flex-col justify-center items-center">
<h2 className="text-2xl font-bold">新增待辦</h2>
<div className="mt-8">
<div className="grid grid-cols-1 gap-[8px] w-[340px]">
<label className="block ">
<span className="text-gray-700">標題</span>
<input
type="text"
className="
mt-1
block
w-full
rounded-md
bg-gray-100
border-transparent
focus:border-gray-500 focus:bg-white focus:ring-0
"
/>
</label>
<label className="block">
<span className="text-gray-700">時間</span>
<input
type="date"
className="
mt-1
block
w-full
rounded-md
bg-gray-100
border-transparent
focus:border-gray-500 focus:bg-white focus:ring-0
"
/>
</label>
<label className="block">
<span className="text-gray-700">詳情描述</span>
<textarea
className="
mt-1
block
w-full
rounded-md
bg-gray-100
border-transparent
focus:border-gray-500 focus:bg-white focus:ring-0
"
rows={3}
defaultValue={""}
/>
</label>
</div>
</div>
</div>
</Modal>
...
我們需要一個 state 來控制彈跳視窗,所以新增一個 state 在 TodoPage,叫做 isOpen :
const [isOpen, setIsOpen] = useState(false);
在需要開啟的地方添加 setIsOpen(true)
,也就是 AddButton,不過在那之前,得修改 AddButton.tsx,讓他接受從外面傳進去的 onClick :
import React from "react";
const AddButton = ({ onClick }) => {
return (
<div className="flex items-center" onClick={onClick}>
<svg
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect width="32" height="32" rx="6" fill="#EDF2F7" />
<path
d="M23.7918 16.5416H17.5418V22.7916H15.4585V16.5416H9.2085V14.4583H15.4585V8.20831H17.5418V14.4583H23.7918V16.5416Z"
fill="black"
/>
</svg>
<span className="ml-[8px]">新增待辦</span>
</div>
);
};
export default AddButton;
在回來 TodoPage 來,為 AddButton 加入功能 :
<AddButton onClick={() => setIsOpen(true)} />
再來就是關掉 Modal 的 x 按鈕 :
<span
className="
font-medium
cursor-pointer
inline-block
bg-gray-200
w-[24px] text-center rounded"
onClick={() => setIsOpen(false)}
>
X
</span>
</div>
切完的 HomePage 如圖,程式碼也會給大家。
好的,加上了一個含有添加新 todo 表單的彈跳視窗,下一個章節要來介紹表單的處理,會更仔細的來看看這些表單元素有什麼神奇之處。