Learning Objectives
- 說明 form 的 action 與 method,比較 GET 與 POST 送出資料的方式
- 依資料種類選擇 input 的 type,並用 label 與 for 把說明文字連到欄位
- 說明 name 與 value 的作用,知道沒有 name 的欄位與沒勾選的核取方塊不會送出
- 用 select、textarea、fieldset 與 legend 組織表單
- 用 required、min、max、pattern、maxlength 等屬性做前端驗證,並說明為什麼伺服器端還要再檢查一次
表單是網頁收資料的方式
報名社團、登入帳號、搜尋課程、上傳作業,這些都是表單(form):使用者在網頁上填資料, 按下送出後,瀏覽器把資料打包成一個請求(request)送到伺服器。
表單寫得好不好,差別很大:
| 寫法 | 使用者的感受 |
|---|---|
| 欄位旁的文字有用 label 連起來 | 點文字就能選到欄位;螢幕閱讀器會唸出「Email,編輯文字」 |
Email 欄位用 type="email" |
手機跳出有 @ 的鍵盤;少了 @ 瀏覽器會先提醒 |
| 欄位有 name | 資料真的送到伺服器,不會「填了卻沒送出」 |
這一課從 form 本身開始,依序看各種輸入欄位、資料怎麼送出,以及驗證。
form、action 與 method
<form action="/signup" method="post">
…欄位…
<button type="submit">報名</button>
</form>
action:資料要送到哪個網址。沒寫的話就送回目前這一頁的網址。method:用哪一種 HTTP 方法送出,常用的是get(沒寫時的預設值)與post。
| GET | POST | |
|---|---|---|
| 資料放在哪裡 | 接在網址後面:/search?q=html&page=2 |
放在請求的本文(body),網址列看不到 |
| 會留在哪裡 | 網址列、瀏覽紀錄、書籤、伺服器的紀錄檔 | 不會出現在網址裡 |
| 適合 | 查詢:搜尋、篩選,結果可以存成書籤或分享 | 會改變資料的動作:報名、留言、登入、上傳檔案 |
密碼、個資這類資料不要用 GET,否則會原封不動留在網址與瀏覽紀錄裡。 (POST 只是不放在網址裡,傳輸過程要靠 HTTPS 加密,這部分在優計算的〈全球資訊網與 HTTP〉文章有說明。)
input 的種類與 label
<input> 是空元素,靠 type 決定它是什麼樣的欄位:
| type | 用途 | 瀏覽器幫你做的事 |
|---|---|---|
text |
一行文字(預設) | |
email |
電子郵件 | 檢查格式;手機鍵盤出現 @ |
password |
密碼 | 輸入的字顯示成圓點 |
number |
數字 | 只能輸入數字,有上下調整鈕 |
date |
日期 | 跳出日期選擇器 |
checkbox |
核取方塊,可以複選 | |
radio |
選項按鈕,同一組只能選一個 | |
file |
選擇檔案上傳 | 開啟檔案選擇視窗 |
每個欄位都要有一個 label(標籤),說明這一格要填什麼。兩種寫法:
<!-- 寫法一:for 對到 input 的 id -->
<label for="email">Email</label>
<input type="email" id="email" name="email">
<!-- 寫法二:把 input 包在 label 裡面 -->
<label>Email <input type="email" name="email"></label>
連起來之後:點 label 的文字就會選到欄位(核取方塊的點擊範圍變大很多),螢幕閱讀器也會唸出欄位的名稱。
placeholder 不能取代 label。placeholder="Email" 是欄位裡的淺灰色提示字,一開始輸入就消失,
使用者打到一半就忘了這格要填什麼;它的顏色通常也很淡,不容易看清楚,螢幕閱讀器也不一定會唸。
placeholder 適合放格式範例(例如「[email protected]」),說明文字一律用 label。
name 與 value:送出去的是什麼
按下送出時,瀏覽器把每個欄位變成一組 name=value:
<input type="text" name="nickname"> <!-- 填了 Amy → nickname=Amy -->
<input type="checkbox" name="course" value="band"> <!-- 勾選 → course=band -->
name是這筆資料的名稱,伺服器用它找到資料。沒有 name 的欄位不會送出,填了也一樣。- 文字欄位的 value 是使用者輸入的內容;核取方塊與選項按鈕的 value 要自己寫。
核取方塊沒寫 value 時,送出的是
course=on,伺服器分不出勾的是哪一個。 - 沒有勾選的核取方塊與選項按鈕不會送出,連 name 都不會出現。
- 停用(
disabled)的欄位也不會送出。
選項按鈕(radio)用同一個 name 分成一組,同一組只能選一個:
<fieldset>
<legend>年級</legend>
<label><input type="radio" name="grade" value="1"> 大一</label>
<label><input type="radio" name="grade" value="2"> 大二</label>
</fieldset>
fieldset 把相關的欄位圍成一組,legend 是這一組的標題;螢幕閱讀器唸到「大一」時會一起唸出「年級」。
另外兩種常用的欄位:
<label for="inst">樂器</label>
<select id="inst" name="instrument"> <!-- 下拉選單 -->
<option value="">請選擇</option>
<option value="guitar">吉他</option>
<option value="bass">貝斯</option>
</select>
<label for="intro">自我介紹</label>
<textarea id="intro" name="intro" rows="4"></textarea> <!-- 多行文字,不是空元素 -->
小測驗:label、name 與 value
<input type="checkbox" name="news"> 沒有寫 value。使用者勾選後送出,伺服器收到什麼?
同一個核取方塊沒有勾選就送出,伺服器收到什麼?
<label for="mail">Email</label> 要和哪一個輸入框連起來?
一份表單填完後,伺服器收到的資料少了「自我介紹」。最可能的原因是?
驗證屬性
HTML 可以直接寫出欄位的規則,送出前瀏覽器會先檢查,不符合就擋下來、不送出,並顯示提示:
| 屬性 | 規則 | 範例 |
|---|---|---|
required |
必填 | <input name="name" required> |
type="email"、type="url" |
格式要像 email、網址 | |
min、max |
數字或日期的範圍 | <input type="number" name="age" min="16" max="99"> |
maxlength、minlength |
字數上限、下限 | <textarea name="intro" maxlength="200"> |
pattern |
用正規表達式規定格式,要整個值都符合 | <input name="sid" pattern="[0-9]{9}"> |
兩個細節:
pattern會自動比對整個值:[0-9]{9}只接受剛好 9 個數字,10 個數字也不行。欄位空白時不檢查 pattern,要必填得另外加required。- 規則寫在 HTML 裡,最好也在 label 或說明文字告訴使用者,例如「學號(9 碼數字)」,不要讓人送出被擋了才知道。
前端驗證不能取代伺服器端的檢查。 瀏覽器的驗證是為了方便使用者,早一點發現打錯;
但任何人都可以用開發者工具刪掉 required、maxlength,或乾脆不透過網頁、直接把請求送到伺服器。
伺服器收到資料時一定要再檢查一次(格式、長度、權限),這是資訊安全的基本原則。
小測驗:送出與驗證
搜尋表單 <form action="/search" method="get"> 裡有 <input name="q">,使用者輸入 css 後送出,瀏覽器會前往哪個網址?
登入表單有帳號與密碼,method 應該用哪一個?
<input name="sid" pattern="[0-9]{9}">,使用者輸入 1234567890(10 個數字)。結果是?
表單的欄位都加了 required 與 maxlength。伺服器端還需要檢查這些資料嗎?
重點整理
form的action是送到哪裡、method是怎麼送:GET 把資料接在網址後面,適合查詢;POST 放在請求本文,適合會改變資料的動作與敏感資料。- 依資料選 input 的
type(email、password、number、date、checkbox、radio、file…),每個欄位都要有label;placeholder 只放格式範例。 - 送出的是 name=value:沒有 name、沒勾選、disabled 的欄位都不會送出;選項按鈕用同一個 name 分成一組。
- 用
fieldset+legend把相關欄位分組;多行文字用textarea,下拉選單用select。 required、min、max、pattern、maxlength讓瀏覽器先檢查;伺服器一定要再檢查一次。
下一課講語意化 HTML:用 header、nav、main、article 這些元素說明頁面每一塊的角色。