網頁表單具有主從架構的關係。 它們被用於發送資料給網頁伺服器,以便其進行處理和儲存。表單本身是客戶端,而伺服器是任何可用於儲存、檢索和在需要時發送資料的儲存機制。
本指南將教導您如何使用 Next.js 創建 Web 表單。
HTML 表單是透過 <form>
這個標籤建立的。它需要由一些屬性和欄位的集合來建立擁有像是文字輸入格、複選框、下拉式選單、按鈕、單選按鈕等功能的表單。
這是一個 HTML 表單的語法:
<!-- 基本的 HTML Form --> <form action="/send-data-here" method="post"> <label for="first">First name:</label> <input type="text" id="first" name="first" /> <label for="last">Last name:</label> <input type="text" id="last" name="last" /> <button type="submit">Submit</button> </form>
前端呈現的樣子:
HTML <form>
標籤充當不同 <input>
元素的容器,例如 <form>
裡面包含 text
欄位以及提交 button
。 讓我們來個別考究這些元素:
action
:這是用於指定提交表單時要將表單資料發送到何處的屬性。 它通常是一個 URL(絕對 URL 或相對 URL)。method
:指定要使用何種 HTTP 方法,即 GET
或 POST
將表單發送出去。<label>
:一種元素,用來替其他表單元素定義標籤。 標籤有助於可存取性,尤其是對於螢幕閱讀器。<input>
:被廣泛用於構建表單欄位的表單元素。 它很大程度上取決於 type
屬性的值。 這些值可以是 text
、checkbox
、email
、radio
等。<button>
:表示一個用於提交表單資料的可點擊按鈕。檢查使用者提供的資訊是否正確的過程。 表單驗證還確保提供的資訊格式是正確的(例如,電子郵件欄位中有一個 @)。 表單驗證有兩種類型:
儘管這兩種類型同樣重要,但本指南將僅著重於客戶端驗證。
客戶端驗證被進一步分類為:
required
、type
、minLength
、maxLength
、pattern
等。required
、type
、minLength
、maxLength
的內建表單驗證required
:指定在提交表單之前必須填寫哪些欄位。type
:指定資料的類型(即數字、電子郵件地址、字串等)。minLength
:指定文字資料字串的最小長度。maxLength
:指定文字資料字串的最大長度。那麼,使用這些屬性的表單看起來可能就像下面這樣:
<!-- 加入內建驗證的 HTML Form --> <form action="/send-data-here" method="post"> <label for="roll">Roll Number</label> <input type="text" id="roll" name="roll" required minlength="10" maxlength="20" /> <label for="name">Name:</label> <input type="text" id="name" name="name" required /> <button type="submit">Submit</button> </form>
有了這些驗證檢查,當使用者嘗試在 Name 欄位為空時提交表單,會在表單中的該欄位位置彈出錯誤。同樣地,只有 10-20 個字元長度的值才能輸入到正式編號(Roll Number)欄位。
表單驗證對於確保使用者以正確的格式提交正確的資料很重要。JavaScript 在客戶端提供了額外級別的驗證以及 HTML 原生表單屬性。開發人員通常更喜歡通過 JavaScript 驗證表單資料,因為與伺服器端驗證相比,它的資料處理速度更快,但是在某些情境下單靠前端驗證可能不太安全,因為惡意使用者總是有辦法向您的伺服器發送格式錯誤的資料。
以下呈現使用 JavaScript 來驗證表單的例子:
<form onsubmit="validateFormWithJS()"> <label for="rollNumber">Roll Number:</label> <input type="text" name="rollNumber" id="rollNumber" /> <label for="name">Name:</label> <input type="text" name="name" id="name" /> <button type="submit">Submit</button> </form> <script> function validateFormWithJS() { const name = document.querySelector('#name').value const rollNumber = document.querySelector('#rollNumber').value if (!name) { alert('Please enter your name.') return false } if (rollNumber.length < 3) { alert('Roll Number should be at least 3 digits long.') return false } } </script>
HTML script 標籤用於在 HTML 中嵌入任何客戶端的 JavaScript。它可以包含行內腳本陳述(如上例所示)或通過 src
屬性指向外部腳本檔案。
本例子驗證使用者的姓名和正式編號。validateFormWithJS()
函數不允許為空,並且正式編號必須至少為三位數。當您點擊提交按鈕時即進行驗證。唯有欄位的值被正確填入後提交,您才會被重定向到下一頁。
要使用 JavaScript 驗證的正則表達式,需透過 pattern
HTML 屬性。正則表達式(通常稱為 RegEx)是描述字串樣式的物件。您只能在 <input>
元素上使用 pattern
屬性。這樣,您可以通過定義自己的規則來使用正則表達式 (RegEx) 驗證輸入值。再次強調,如果值與定義的模式不匹配,輸入欄位將彈出錯誤。
下面的例子呈現在 input
元素上使用 pattern
屬性的樣子:
<form action="/action_page.php"> <label for="pswrd">Password:</label> <input type="password" id="pswrd" name="pswrd" pattern="[a-z0-9]{1,15}" title="Password should be digits (0 to 9) or alphabets (a to z)." /> <button type="submit">Submit</button> </form>
密碼表單欄位只能包含數字(0 到 9)、小寫字母(a 到 z),並且長度不得超過 15 個字符。不允許使用其他字符(#、$、& 等)。此規則以 RegEx 寫成 [a-z0-9]{1,15}
。
欲了解更多有關 HTML 表單的資訊,請查看 MDN Web Docs。
在接下来的部分中,您將使用 Next.js 在 React 中建立表單。
欲建立一個新的 Next.js 應用程式,您可以使用 create-next-app 快速建立。在命令行終端機中,執行以下命令:
npx create-next-app
本例使用 next-forms
,使用上述命令加上專案名稱創建您的專案。接下來 cd
進入專案資料夾,並執行 npm run dev
或 yarn dev
命令啟動開發用伺服器。
打開終端機印出的 URL 以確保您的應用程式成功執行。
客戶端和伺服器都將使用 Next.js 建置。在伺服器部分,創建一個 API 端點,您將在其中發送表單資料。
Next.js 提供了一個基於檔案的路由系統,該系統以 頁面概念 為基礎建立而成。pages/api
資料夾中的所有檔案都會映射到 /api/*
,並將被視為 API 端點而不是頁面。這個 API 端點 將僅在伺服器端。
在 pages/api
路由下,創建一個名為 form.js
的檔案,打開後貼上這段用 Node.js 編寫的程式碼:
export default function handler(req, res) { // 獲取在 request 的 body 中被使用者提交的資料 const body = req.body // 可選日誌記錄用於查看正在執行 next.js 應用程式的終端機顯現的 response console.log('body: ', body) // 檢查名字和姓氏,如果有缺漏則提前回傳 if (!body.first || !body.last) { // 發送 HTTP 客戶端錯誤狀態碼 return res.status(400).json({ data: 'First or last name not found' }) } // 發送 HTTP 成功狀態碼 res.status(200).json({ data: `${body.first} ${body.last}` }) }
這個表單 handler
函式將接收來自客戶端的請求req
(即提交的表單資料)。作為回報,它將以 JSON 格式回傳一個響應 res
,其中包含名字和姓氏。您可以在 http://localhost:3000/api/form
存取此 API 端點,或者在部署時將 localhost URL 替換為實際的 Vercel 部署 URL。
此外,您還可以將此 API 附加 MongoDB 或 Google Sheets 等資料庫。這樣,您提交的表單資料將被安全儲存以便之後使用。在本指南,並未使用資料庫,而是將相同的資料回傳給使用者以演示它是如何完成的。
您現在可以在表單的 action
屬性中使用 /api/form
相對端點。當表單透過 POST
HTTP 方法(用於發送資料)提交時,即表示您正在向伺服器發送表單資料。
<form action="/api/form" method="post"> <label for="first">First name:</label> <input type="text" id="first" name="first" /> <label for="last">Last name:</label> <input type="text" id="last" name="last" /> <button type="submit">Submit</button> </form>
如果您提交此表單,它會將資料提交到表單 API 端點/api/form
。然後伺服器做出響應,通常處理數據並加載由 action 屬性定義的 URL,會使新的頁面載入。因此,在這個例子中,您將被重定向到 http://localhost:3000/api/form
,並帶有來自伺服器的以下響應。
您已經為表單提交功能創建了 Next.js API 路由。現在是時候使用 React 在 Next.js 中配置客戶端(表單本身)了。第一步將擴展您對 HTML 表單的知識並將其轉換為 React(使用 JSX)。
這是與上面例子相同的表單,使用 JSX 在 React 函式元件 中編寫而成。
export default function Form() { return ( <form action="/api/form" method="post"> <label htmlFor="first">First Name</label> <input type="text" id="first" name="first" required /> <label htmlFor="last">Last Name</label> <input type="text" id="last" name="last" required /> <button type="submit">Submit</button> </form> ) }
以下是做出的變化:
for
屬性更改為 htmlFor
。(因為 for
是 JavaScript 中的 for
迴圈保留字,所以 React 元素使用 htmlFor
代替。)action
屬性現在有一個相對 URL,它是表單的 API 端點。這樣就完成了基於 Next.js 的表單基本結構。
您可以查看我們在此處作為範例建立的 next-forms 範例儲存庫完整源碼。歡迎複製它並即刻開始嘗試。本例子使用 create-next-app 建立,您可以在
/styles/global.css
檔案中預覽基本的表單 CSS 樣式。
JavaScript 為我們的網頁應用程式帶來了交互性,但有時您需要控制 JavaScript 包變得過大,或者訪問您網站的訪客可能禁用了 JavaScript。
使用者為何要禁用 JavaScript 的幾個原因:
無論出於何種原因,禁用 JavaScript 都會影響網站的部分或全部功能。
接下來打開 next-forms
資料夾。在 /pages
資料夾中,建立一個檔案 no-js-form.js
。
快速提示:在 Next.js 中,頁面是從 pages 目錄中的
.js
、.jsx
、.ts
或.tsx
檔案導出的 React 元件。每個頁面都會根據其檔案名稱配置一個路由。範例:如果您建立
pages/no-js-form.js
,它將可以在your-domain.tld/no-js-form
被存取。
讓我們延續使用上面範例的程式碼:
export default function PageWithoutJSbasedForm() { return ( <form action="/api/form" method="post"> <label htmlFor="first">First Name</label> <input type="text" id="first" name="first" required /> <label htmlFor="last">Last Name</label> <input type="text" id="last" name="last" required /> <button type="submit">Submit</button> </form> ) }
在禁用 JavaScript 的情況下,當您點擊提交按鈕時,會觸發一個事件,它會收集表單資料並將其以 POST
HTTP method
發送到我們在 action
屬性中定義的表單 API 端點。您將被重定向到 /api/form
端點,這就是表單 action
的工作方式。
表單資料將作為請求 req
提交給上面編寫的伺服器表單處理函式例子。它將處理資料並回傳一個 JSON 字串作為響應 res
,其中包含您提交的姓名。
為了改善體驗,您可以回傳一個響應,將使用者重定向到一個表示感謝他們提交表單的頁面。
在 /pages
中,您將建立另一個名為 js-form.js
的檔案。這將在您的 Next.js 應用程式上創建一個 /js-form
頁面。
現在,一旦表單被提交,我們會阻止表單預設的重新加載頁面行為。當我們獲取表單資料,會將其轉換為 JSON 字符串,然後發送到我們的伺服器,即 API 端點。最後,我們的伺服器將響應使用者提交的姓名。所有這一切都透過一個基本的 JavaScript handleSubmit()
函式實現。
這是這個函式的樣子。具有充分的註解,讓您了解每個步驟:
export default function PageWithJSbasedForm() { // 處理表單提交事件 const handleSubmit = async (event) => { // 停止表單提交和更新頁面。(取消事件預設行為) event.preventDefault() // 從表單獲取資料 const data = { first: event.target.first.value, last: event.target.last.value, }; // 將要發送到伺服器的資料轉為 JSON 格式 const JSONdata = JSON.stringify(data) // 我們要發送表單資料的 API 端點 const endpoint = "/api/form" // 產生要發送到伺服器的請求 const options = { // 使用 POST 方法,因為我們要發送資料。 method: "POST", // 告知伺服器我們發送的是 JSON。 headers: { "Content-Type": "application/json", }, // HTTP 請求的 Body 是我們上面建立好的 JSON data body: JSONdata, } // 將表單資料發送到我們部屬在 Vercel 上的表單 API 並獲取回傳的響應。 const response = await fetch(endpoint, options) // 將從伺服器得到的響應資料轉為 JSON // 如果伺服器回傳被提交的姓名,則代表表單功能正常運作。 const result = await response.json() alert(`Is this your full name: ${result.data}`) } return ( // 在使用者提交時,我們將事件傳遞給 handleSubmit()。 <form onSubmit={handleSubmit}> <label htmlFor="first">First Name</label> <input type="text" id="first" name="first" required /> <label htmlFor="last">Last Name</label> <input type="text" id="last" name="last" required /> <button type="submit">Submit</button> </form> ) }
這是一個 Next.js 頁面,帶有一個名為 PageWithJSbasedForm
的 React 函式元件,其中包含一個用 JSX 編寫的 <form>
元素。<form>
元素沒有任何 action。 相反地,我們使用 onSubmit
事件處理器將資料發送到我們的 {handleSubmit}
函式。
handleSubmit()
函式通過一系列步驟處理表單資料:
event.preventDefault()
阻止 <form>
元素更新整個頁面。data
的 JavaScript 物件,其中包含表單中的 first
和 last
值。JSON.stringify(data)
將資料轉換為 JSON。POST
方法,使用 fetch()
將資料發送到我們的 /api/form
端點。本指南涵蓋以下內容:
form
元素req
及 res
。有關更詳盡的資訊請參閱 Next.js 學習課程。