# 表單標簽
表單(form)是用戶輸入信息與網頁互動的一種形式。大多數情況下,用戶提交的信息會發給服務器,比如網站的搜索欄就是表單。
表單由一種或多種的小部件組成,比如輸入框、按鈕、單選框或復選框。這些小部件稱為控件(controls)。
## 1.`<form>`
### 1.1 簡介
`<form>`標簽用來定義一個表單,所有表單內容放到這個容器元素之中。
~~~
<form>
<!-- 各種表單控件-->
</form>
~~~
上面代碼就是表單的基本形式。
下面是一個比較常見的例子。
~~~
<form action="https://example.com/api" method="post">
<label for="POST-name">用戶名:</label>
<input id="POST-name" type="text" name="user">
<input type="submit" value="提交">
</form>
~~~
上面代碼就是一個表單,一共包含三個控件:一個`<label>`標簽,一個文本輸入框,一個提交按鈕。其中,文本輸入框的`name`屬性是`user`,表示將向服務器發送一個鍵名為`user`的鍵值對,鍵值就是這個控件的`value`屬性,等于用戶輸入的值。
用戶在文本輸入框里面,輸入用戶名,比如`foobar`,然后點擊提交按鈕,瀏覽器就會向服務器`https://example.com/api`發送一個 POST 請求,發送`user=foobar`這樣一段數據。
`<form>`常用屬性。
* `action`:服務器接收數據的 URL。
* `method`:提交數據的 HTTP 方法,可能的值有`post`(表單數據作為 HTTP 數據體發送),`get`(表單數據作為 URL 的查詢字符串發送),`dialog`(表單位于`<dialog>`內部使用)。
* `enctype`:當`method`屬性等于`post`時,該屬性指定提交給服務器的 MIME 類型。可能的值為`application/x-www-form-urlencoded`(默認值),`multipart/form-data`(文件上傳的情況),`text/plain`。
* `target`:在哪個窗口展示服務器返回的數據,可能的值有`_self`(當前窗口),`_blank`(新建窗口),`_parent`(父窗口),`_top`(頂層窗口),`<iframe>`標簽的`name`屬性(即表單返回結果展示在`<iframe>`窗口)。
### 1.2 encrypt 屬性
`<form>`表單的`encrypt`屬性,指定了采用 POST 方法提交數據時,瀏覽器給出的數據的 MIMI 類型。該屬性可以取以下值。
(1)`application/x-www-form-urlencoded`
`application/x-www-form-urlencoded`是默認類型,控件名和控件值都要轉義(空格轉為`+`號,非數字和非字母轉為`%HH`的形式,換行轉為CR LF),控件名和控件值之間用`=`分隔。控件按照出現順序排列,控件之間用`&`分隔。
(2)`multipart/form-data`
`multipart/form-data`主要用于文件上傳。這個類型上傳大文件時,會將文件分成多塊傳送,每一塊的 HTTP 頭信息都有`Content-Disposition`屬性,值為`form-data`,以及一個`name`屬性,值為控件名。
~~~
Content-Disposition: form-data; name="mycontrol"
~~~
下面是上傳文件的表單。
~~~
<form action="https://example.com/api"
enctype="multipart/form-data"
method="post">
用戶名:<input type="text" name="submit-name"><br>
文件:<input type="file" name="files"><br>
<input type="submit" value="上傳"> <input type="reset" value="清除">
</form>
~~~
上面代碼中,輸入用戶名`Larry`,選中一個`file1.txt`文件,然后點擊“上傳”。
## 2.`<label>`
`<label>`標簽是一個行內元素,提供控件的文字說明,幫助用戶理解控件的目的。
~~~
<label for="user">用戶名:</label>
<input type="text" name="user" id="user">
~~~
上面代碼中,輸入框前面會有文字說明“用戶名:”。
`<label>`的一大優勢是增加了控件的可用性。有些控件比較小(比如單選框),不容易點擊,那么點擊對應的`<label>`標簽,也能選中該控件。點擊`<label>`,就相當于控件本身的`click`事件。
`<label>`的`for`屬性關聯相對應的控件,它的值是對應控件的`id`屬性。所以,控件最好設置`id`屬性。
控件也可以放在`<label>`之中,這時不需要`for`屬性和`id`屬性。
~~~
<label>用戶名:
<input type="text" name="user">
</label>
~~~
`<label>`的屬性如下。
* `for`:關聯控件的`id`屬性。
* `form`:關聯表單的`id`屬性。設置了該屬性后,`<label>`可以放置在頁面的任何位置,否則只能放在`<form>`內部。
## 3.`<input>`
### 3.1 簡介
`<input>`標簽是一個行內元素,用來接收用戶的輸入。它是一個單獨使用的標簽,沒有結束標志。
它有多種類型,取決于`type`屬性的值,默認值是`text`,表示一個輸入框。
~~~
<input>
<!-- 等同于 -->
<input type="text">
~~~
上面代碼會生成一個單行的輸入框,用戶可以在里面輸入文本。
`<input>`的屬性非常多,有些屬性是某個類型專用的,放在下文的“類型”部分介紹。這里介紹一些所有類型的共同屬性。
* `autofocus`:布爾屬性,是否在頁面加載時自動獲得焦點。
* `disabled`:布爾屬性,是否禁用該控件。一旦設置,該控件將變灰,用戶可以看到,但是無法操作。
* `form`:關聯表單的`id`屬性。設置了該屬性后,控件可以放置在頁面的任何位置,否則只能放在`<form>`內部。
* `list`:關聯的`<datalist>`的`id`屬性,設置該控件相關的數據列表,詳見后文。
* `name`:控件的名稱,主要用于向服務器提交數據時,控件鍵值對的鍵名。注意,只有設置了`name`屬性的控件,才會向服務器提交,不設置就不會提交。
* `readonly`:布爾屬性,是否為只讀。
* `required`:布爾屬性,是否為必填。
* `type`:控件類型,詳見下文。
* `value`:控件的值。
### 3.2 類型
`type`屬性決定了`<input>`的形式。該屬性可以取以下值。
#### (1)`type="text"`
`type="text"`是普通的文本輸入框,用來輸入單行文本。如果用戶輸入換行符,換行符會自動從輸入中刪除。
~~~
<input type="text" id="name" name="name" required
minlength="4" maxlength="8" size="10">
~~~
`text`輸入框有以下配套屬性。
* `maxlength`:可以輸入的最大字符數,值為一個非負整數。
* `minlength`:可以輸入的最小字符數,值為一個非負整數,且必須小于`maxlength`。
* `pattern`:用戶輸入必須匹配的正則表達式,比如要求用戶輸入4個~8個英文字符,可以寫成`pattern="[a-z]{4,8}"`。如果用戶輸入不符合要求,瀏覽器會彈出提示,不會提交表單。
* `placeholder`:輸入字段為空時,用于提示的示例值。只要用戶沒有任何字符,該提示就會出現,否則會消失。
* `readonly`:布爾屬性,表示該輸入框是只讀的,用戶只能看,不能輸入。
* `size`:表示輸入框的顯示長度有多少個字符寬,它的值是一個正整數,默認等于20。超過這個數字的字符,必須移動光標才能看到。
* `spellcheck`:是否對用戶輸入啟用拼寫檢查,可能的值為`true`或`false`。
#### (2)`type="search"`
`type="search"`是一個用于搜索的文本輸入框,基本等同于`type="text"`。某些瀏覽器會在輸入的時候,在輸入框的尾部顯示一個刪除按鈕,點擊就會刪除所有輸入,讓用戶從頭開始輸入。
~~~
<form>
<input type="search" id="mySearch" name="q"
placeholder="輸入搜索詞……" required>
<input type="submit" value="搜索">
</form>
~~~
#### (3)`type="button"`
`type="button"`是沒有默認行為的按鈕,通常腳本指定`click`事件的監聽函數來使用。
~~~
<input type="button" value="點擊">
~~~
建議盡量不使用這個類型,而使用`<button>`標簽代替,一則語義更清晰,二則`<button>`標簽內部可以插入圖片或其他 HTML 代碼。
#### (4)`type="submit"`
`type="submit"`是表單的提交按鈕。用戶點擊這個按鈕,就會把表單提交給服務器。
~~~
<input type="submit" value="提交">
~~~
如果不指定`value`屬性,瀏覽器會在提交按鈕上顯示默認的文字,通常是`Submit`。
#### (5)`type="reset"`
`type="reset"`是一個重置按鈕,用戶點擊以后,所有表格控件重置為初始值。
~~~
<input type="reset" value="重置">
~~~
如果不設置`value`屬性,瀏覽器會在按鈕上面加上默認文字,通常是`Reset`。
這個控件用處不大,用戶點錯了還會使得所有已經輸入的值都被重置,建議不要使用。
#### (6)`type="checkbox"`
`type="checkbox"`是復選框,允許選擇或取消選擇該選項。
~~~
<input type="checkbox" name="agreement" checked>
<label for="agreement">是否同意</label>
~~~
上面代碼會在文字前面,顯示一個可以點擊的選擇框,點擊可以選中,再次點擊可以取消。上面代碼中,`checked`屬性表示默認選中。
`value`屬性的默認值是`on`。也就是說,如果沒有設置`value`屬性,以上例來說,選中復選框時,會提交`agreement=on`。如果沒有選中,提交時不會有該項。
多個相關的復選框,可以放在`<fieldset>`里面。
~~~
<fieldset>
<legend>你的興趣</legend>
<div>
<input type="checkbox" id="coding" name="interest" value="coding">
<label for="coding">編碼</label>
</div>
<div>
<input type="checkbox" id="music" name="interest" value="music">
<label for="music">音樂</label>
</div>
</fieldset>
~~~
上面代碼中,如果用戶同時選中兩個復選框,提交的時候就會有兩個`name`屬性,比如`interest=coding&interest=music`。
#### (7)`type="radio"`
`type="radio"`是單選框,表示一組選擇之中,只能選中一項。單選框通常為一個小圓圈,選中時會被填充或突出顯示。
~~~
<fieldset>
<legend>性別</legend>
<div>
<input type="radio" id="male" name="gender" value="male">
<label for="male">男</label>
</div>
<div>
<input type="radio" id="female" name="gender" value="female">
<label for="female">女</label>
</div>
</fieldset>
~~~
上面代碼中,性別只能在兩個選項之中,選擇一項。
注意,多個單選框的`name`屬性的值,應該都是一致的。提交到服務器的就是選中的那個值。
該類型的配套屬性如下。
* `checked`:布爾屬性,表示是否默認選中當前項。
* `value`:用戶選中該項時,提交到服務器的值,默認為`on'`。
#### (8)`type="password"`
`type="password"`是一個密碼輸入框。用戶的輸入會被遮擋,字符通常顯示星號(`*`)或點(`·`)。
~~~
<input type="password" id="pass" name="password"
minlength="8" required>
~~~
如果用戶輸入內容包含換行符(`U+000A`)和回車符(`U+000D`),瀏覽器會自動將這兩個字符過濾掉。
該類型的配套屬性如下。
* `maxlength`:可以輸入的最大字符數。
* `minlength`:可以輸入的最少字符數。
* `pattern`:輸入必須匹配的正則表達式。
* `placeholder`:輸入為空時的顯示文本。
* `readonly`:布爾屬性,該輸入框是否只讀。
* `size`:一個非負整數,表示輸入框的顯示長度為多少個字符。
* `autocomplete`:是否允許自動填充,可能的值有`on`(允許自動填充)、`off`(不允許自動填充)、`current-password`(填入當前網站保存的密碼)、`new-password`(自動生成一個隨機密碼)。
* `inputmode`:允許用戶輸入的數據類型,可能的值有`none`(不使用系統輸入法)、`text`(標準文本輸入)、`decimal`(數字,包含小數)、`numeric`(數字0-9)等。
#### (9)`type="file"`
`type="file"`是一個文件選擇框,允許用戶選擇一個或多個文件,常用于文件上傳功能。
~~~
<input type="file"
id="avatar" name="avatar"
accept="image/png, image/jpeg">
~~~
該類型有以下屬性。
* `accept`:允許選擇的文件類型,使用逗號分隔,可以使用 MIME 類型(比如`image/jpeg`),也可以使用后綴名(比如`.doc`),還可以使用`audio/*`(任何音頻文件)、`video/*`(任何視頻文件)、`image/*`(任何圖像文件)等表示法。
* `capture`:用于捕獲圖像或視頻數據的源,可能的值有`user`(面向用戶的攝像頭或麥克風),`environment`(外接的攝像頭或麥克風)。
* `multiple`:布爾屬性,是否允許用戶選擇多個文件。
#### (10)`type="hidden"`
`type="hidden"`是一個不顯示在頁面的控件,用戶無法輸入它的值,主要用來向服務器傳遞一些隱藏信息。比如,CSRF 攻擊會偽造表單數據,那么使用這個控件,可以為每個表單生成一個獨一無二的隱藏編號,防止偽造表單提交。
~~~
<input id="prodId" name="prodId" type="hidden" value="xm234jq">
~~~
上面這個控件,頁面上是看不見的。用戶提交表單的時候,瀏覽器會將`prodId=xm234jq`發給服務器。
## 4.`<button>`
`<button>`標簽會生成一個可以點擊的按鈕,沒有默認行為,通常需要用`type`屬性或腳本指定按鈕的功能。
~~~
<button>點擊</button>
~~~
上面代碼會產生一個按鈕,上面的文字就是“點擊”。
`<button>`內部不僅放置文字,還可以放置圖像,這可以形成圖像按鈕。
~~~
<button name="search" type="submit">
<img src="search.gif">搜索
</button>
~~~
## 5.`<select>`
`<select>`標簽用于生成一個下拉菜單。
~~~
<label for="pet-select">寵物:</label>
<select id="pet-select" name="pet-select">
<option value="">--請選擇一項--</option>
<option value="dog">狗</option>
<option value="cat">貓</option>
<option value="others">其他</option>
</select>
~~~
上面代碼中,`<select>`生成一個下拉菜單,菜單標題是“--請選擇一項--”,最右側有一個下拉箭頭。點擊下拉箭頭,會顯示三個菜單項,供用戶點擊選擇。
下拉菜單的菜單項由`<option>`標簽給出,每個`<option>`代表可以選擇的一個值。選中的`<option>`的`value`屬性,就是`<select>`控件發送的服務器的值。
`<option>`有一個布爾屬性`selected`,一旦設置,就表示該項是默認選中的菜單項。
~~~
<select name="choice">
<option value="first">First Value</option>
<option value="second" selected>Second Value</option>
<option value="third">Third Value</option>
</select>
~~~
上面代碼中,第二項`Second Value`是默認選中的。頁面加載的時候,會直接顯示在下拉菜單上。
`<select>`有如下屬性。
* `autofocus`:布爾屬性,頁面加載時是否自動獲得焦點。
* `disabled`:布爾屬性,是否禁用當前控件。
* `form`:關聯表單的`id`屬性。
* `multiple`:布爾屬性,是否可以選擇多個菜單項。默認情況下,只能選擇一項。一旦設置,多數瀏覽器會顯示一個滾動列表框。用戶可能需要按住`Shift`或其他功能鍵,選中多項。
* `name`:控件名。
* `required`:布爾屬性,是否為必填控件。
* `size`:設置了`multiple`屬性時,頁面顯示時一次可見的行數,其他行需要滾動查看。
## 6.`<textarea>`
`<textarea>`是一個塊級元素,用來生成多行的文本框。
~~~
<textarea id="story" name="story"
rows="5" cols="33">
這是一個很長的故事。
</textarea>
~~~
上面代碼會生成一個長度為5行,寬度為33個字符的文本框。
該標簽有如下屬性。
* `autofocus`:布爾屬性,是否自動獲得焦點。
* `cols`:文本框的寬度,單位為字符,默認值為20。
* `disabled`:布爾屬性,是否禁用該控件。
* `form`:關聯表單的`id`屬性。
* `maxlength`:允許輸入的最大字符數。如果未指定此值,用戶可以輸入無限數量的字符。
* `minlength`:允許輸入的最小字符數。
* `name`:控件的名稱。
* `placeholder`:輸入為空時顯示的提示文本。
* `readonly`:布爾屬性,控件是否為只讀。
* `required`:布爾屬性,控件是否為必填。
* `rows`:文本框的高度,單位為行。
* `spellcheck`:是否打開瀏覽器的拼寫檢查。可能的值有`true`(打開),`default`(由父元素或網頁設置決定),`false`(關閉)。
* `wrap`:輸入的文本是否自動換行。可能的值有`hard`(瀏覽器自動插入換行符`CR + LF`,使得每行不超過控件的寬度),`soft`(輸入內容超過寬度時自動換行,但不會加入新的換行符,并且瀏覽器保證所有換行符都是`CR + LR`,這是默認值),`off`(關閉自動換行,單行長度超過寬度時,會出現水平滾動條)。