新增完專案後,就可以開始建立這個網站的 UI 了,首先要看這個網站有哪些功能,然後來決定需要哪些畫面,這個網站目前有以下幾個功能:
最後有一個產生 QR Code 的按鈕,按下去之後就會產生 QR Code,所以我們需要建立四個區塊,這些區塊就用 component 來處理。
所以我們就先在 app
資料夾下新增一個 components
資料夾,並且新增四個檔案:
$ mkdir app/components
$ touch app/components/SelectType.tsx app/components/TextInput.tsx app/components/SizeSlider.tsx app/components/ColorPicker.tsx
在每個 component 中,都需要有一個 state 來儲存使用者的選擇,這裡我們先在 page.tsx
中使用 useState
來建立各個 component 的 state。
由於在 Next.js 版本 13 之後,在
app
資料夾下的每一個檔案預設都會是 Server Side Rendering(SSR),而在 SSR 中不能使用任何 React Hooks。如果要使用 React Hooks,就要在最前面加上"use client"
。
// app/page.tsx
'use client'
import { useState, FormEvent } from 'react'
import { TextInput, SelectType, SizeSlider, ColorPicker } from './components'
export default function Home() {
const [text, setText] = useState<string>('')
const [qrType, setQrType] = useState<string>('URL')
const [qrSize, setQrSize] = useState<number>(500)
const [qrColor, setQrColor] = useState<string>('#000000')
const [qrBgColor, setQrBgColor] = useState<string>('#ffffff')
return (
// 省略
)
}
第一個 component 是 SelectType
,這個 component 是用來選擇 QR Code 的類型,這裡我們使用 select
來建立選項,並且使用從 page.tsx
的 props 來管理使用者的選擇,接下來的三個 component 也是一樣的做法。
// app/components/SelectType.tsx
import { FC, SetStateAction, Dispatch } from 'react'
interface SelectTypeProps {
qrType: string
setQrType: Dispatch<SetStateAction<string>>
}
const SelectType: FC<SelectTypeProps> = ({
qrType,
setQrType
}) => {
return (
<div className='mb-4'>
<label className='block font-bold mb-2'>選擇 QR Code 類型</label>
<select
className='w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300'
value={qrType}
onChange={(e) => setQrType(e.target.value)}
>
<option value='URL'>URL</option>
<option value='電話'>電話</option>
<option value='地址'>地址</option>
<option value='Email'>Email</option>
</select>
</div>
)
}
export default SelectType
第二個 component 是 TextInput
,這個 component 是用來輸入文字,這裡我們使用 input
來建立輸入框。
import { FC, SetStateAction, Dispatch } from 'react'
interface TextInputProps {
text: string
setText: Dispatch<SetStateAction<string>>
}
const TextInput: FC<TextInputProps> = ({ text, setText }) => (
<div className='mb-4'>
<label className='block font-bold mb-2'>輸入文字</label>
<input
type='text'
className='w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300'
value={text}
onChange={(e) => setText(e.target.value)}
/>
</div>
)
export default TextInput
第三個 component 是 SizeSlider
,這個 component 是用來調整圖片大小,這裡我們使用 input
來建立輸入框,並且設定 type='range'
,這樣就可以使用滑動條來調整圖片大小。
import { FC, SetStateAction, Dispatch } from 'react'
interface SizeSliderProps {
qrSize: number
setQrSize: Dispatch<SetStateAction<number>>
}
const SizeSlider: FC<SizeSliderProps> = ({ qrSize, setQrSize }) => {
return (
<div className='mb-4'>
<label className='block font-bold mb-2'>調整圖片大小</label>
<input
type='range'
min='100'
max='2000'
value={qrSize}
onChange={(e) => setQrSize(parseInt(e.target.value))}
/>
</div>
)
}
export default SizeSlider
第四個 component 是 ColorPicker
,這個 component 是用來調整圖片顏色,這裡我們使用 input
來建立輸入框,並且設定 type='color'
,這樣就可以使用顏色選擇器來調整圖片顏色。
import { FC, SetStateAction, Dispatch } from 'react'
interface ColorPickerProps {
label: string
color: string
setColor: Dispatch<SetStateAction<string>>
}
const ColorPicker: FC<ColorPickerProps> = ({
label,
color,
setColor
}) => {
return (
<div className='mb-4'>
<label className='block font-bold mb-2'>{label}</label>
<input
type='color'
value={color}
onChange={(e) => setColor(e.target.value)}
/>
</div>
)
}
export default ColorPicker
最後我們就可以把這些 component 整合到 page.tsx
中,並且設定產生 QR Code 的按鈕。
import { TextInput, SelectType, SizeSlider, ColorPicker } from './components'
export default function Home() {
// 省略
const generateQRCode = (e: FormEvent) => {
e.preventDefault()
// 這裡是產生 QR code 的邏輯,之後再補上
}
return (
<main className='flex min-h-screen flex-col items-center justify-between p-24'>
<div className='container mx-auto p-4'>
<h1 className='text-3xl mb-4'>QR Code 製造器</h1>
<form onSubmit={generateQRCode} className='flex flex-col gap-y-5'>
<SelectType qrType={qrType} setQrType={setQrType} />
<TextInput text={text} setText={setText} />
<div className='flex items-center justify-evenly'>
<SizeSlider qrSize={qrSize} setQrSize={setQrSize} />
<ColorPicker
label='選擇顏色'
color={qrColor}
setColor={setQrColor}
/>
<ColorPicker
label='選擇背景顏色'
color={qrBgColor}
setColor={setQrBgColor}
/>
</div>
<div className='flex justify-center mt-5'>
<button
type='submit'
className='bg-green-500 hover:bg-green-100 text-white hover:text-slate-700 font-bold py-2 px-4 rounded text-center'
>
產生 QR Code
</button>
</div>
</form>
</div>
</main>
)
}
最後的畫面如下:
今天的內容就到這邊,下一篇會試著跟後端 API 串接,並且產生 QR Code。