使用 Next.js 建立表單

網頁表單具有主從架構的關係。 它們被用於發送資料給網頁伺服器,以便其進行處理和儲存。表單本身是客戶端,而伺服器是任何可用於儲存、檢索和在需要時發送資料的儲存機制。

本指南將教導您如何使用 Next.js 創建 Web 表單。

Part 1:HTML 表單

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 forms

HTML <form> 標籤充當不同 <input> 元素的容器,例如 <form> 裡面包含 text 欄位以及提交 button。 讓我們來個別考究這些元素:

  • action:這是用於指定提交表單時要將表單資料發送到何處的屬性。 它通常是一個 URL(絕對 URL 或相對 URL)。
  • method:指定要使用何種 HTTP 方法,即 GETPOST 將表單發送出去。
  • <label>:一種元素,用來替其他表單元素定義標籤。 標籤有助於可存取性,尤其是對於螢幕閱讀器。
  • <input>:被廣泛用於構建表單欄位的表單元素。 它很大程度上取決於 type 屬性的值。 這些值可以是 textcheckboxemailradio 等。
  • <button>:表示一個用於提交表單資料的可點擊按鈕。

表單驗證

檢查使用者提供的資訊是否正確的過程。 表單驗證還確保提供的資訊格式是正確的(例如,電子郵件欄位中有一個 @)。 表單驗證有兩種類型:

  • 客戶端:驗證在瀏覽器完成
  • 伺服器端:驗證在伺服器完成

儘管這兩種類型同樣重要,但本指南將僅著重於客戶端驗證。

客戶端驗證被進一步分類為:

  • 內建:使用基於 HTML 的屬性,例如 requiredtypeminLengthmaxLengthpattern 等。
  • 基於 JavaScript:利用 JavaScript 編碼的驗證.

使用 requiredtypeminLengthmaxLength 的內建表單驗證

  • 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)欄位。

form validation

基於 JavaScript 的表單驗證

表單驗證對於確保使用者以正確的格式提交正確的資料很重要。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() 函數不允許為空,並且正式編號必須至少為三位數。當您點擊提交按鈕時即進行驗證。唯有欄位的值被正確填入後提交,您才會被重定向到下一頁。

js-validation

使用正則表達式進行表單驗證

要使用 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}

form-validate-regex

欲了解更多有關 HTML 表單的資訊,請查看 MDN Web Docs

Part 2:專案設置

在接下来的部分中,您將使用 Next.js 在 React 中建立表單。

欲建立一個新的 Next.js 應用程式,您可以使用 create-next-app 快速建立。在命令行終端機中,執行以下命令:

npx create-next-app

本例使用 next-forms,使用上述命令加上專案名稱創建您的專案。接下來 cd 進入專案資料夾,並執行 npm run devyarn dev 命令啟動開發用伺服器。

打開終端機印出的 URL 以確保您的應用程式成功執行。

Part 3:設置 Next.js 表單 API 路由

客戶端和伺服器都將使用 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 等資料庫。這樣,您提交的表單資料將被安全儲存以便之後使用。在本指南,並未使用資料庫,而是將相同的資料回傳給使用者以演示它是如何完成的。

不使用 JavaScript 的表單提交

您現在可以在表單的 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,並帶有來自伺服器的以下響應。

form-no-js

Part 4: 在 Next.js 中配置表單

您已經為表單提交功能創建了 Next.js API 路由。現在是時候使用 React 在 Next.js 中配置客戶端(表單本身)了。第一步將擴展您對 HTML 表單的知識並將其轉換為 React(使用 JSX)。

這是與上面例子相同的表單,使用 JSXReact 函式元件 中編寫而成。

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 樣式。

forms with nextjs

Part 5: 不使用 JavaScript 的表單提交

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,其中包含您提交的姓名。

為了改善體驗,您可以回傳一個響應,將使用者重定向到一個表示感謝他們提交表單的頁面。

Part 6: 啟用 JavaScript 的表單提交

/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 物件,其中包含表單中的 firstlast 值。
  • JSON 是一種與語言無關的資料傳輸格式。所以我們使用 JSON.stringify(data) 將資料轉換為 JSON。
  • 然後我們透過 JSON 和 HTTP POST 方法,使用 fetch() 將資料發送到我們的 /api/form 端點。
  • 伺服器回傳一個響應,其中包含使用者提交的姓名。嗚呼! 🥳

總結

本指南涵蓋以下內容:

  • 基本的 HTML form 元素
  • 理解使用 React.js 表單
  • 使用以及不使用 JavaScript 驗整表單資料
  • 使用 Next.js API 路由來處理來自客戶端與伺服器的 reqres

有關更詳盡的資訊請參閱 Next.js 學習課程

本篇文章由0xmimiQ

0xmimiQ

貢獻翻譯。瞭解如何參與貢獻