表單基礎知識
在HTML中,表單是由<form>
元素來表示的,而在JS中,表單對應的則是HTMLFormElement
類型。HTMLFormElement
繼承了HTMLElement
,因而與其他HTML元素具有相同的默認屬性。不過HTMLFormElement
也有它獨有的屬性和方法:
-
acceptCharset
:服務器能夠處理的字符集;等價于HTML的accept-charset
特性。 -
action
:接受請求的URL;等價于HTML的action
特性。 -
elements
:表單中所有控件的集合。 -
enctype
:請求的編碼類型;等價于HTML的enctype
特性。 -
length
:表單中控件的數量。 -
method
:要發送的HTTP請求類型;等價于HTML的method
特性。 -
name
:表單的名稱;等價于HTML的name
特性。 -
reset()
:將所有表單域重置為默認值。 -
submit()
:提交表單。 -
target
:用于發送請求和接收響應的窗口名稱;等價于HTML的target
特性。
除了通過id
取得<form>
元素引用,還可以通過document.forms
取得頁面中所有表單。在這個集合中可以通過數值索引或name
值來取得特定的表單:
var form = document.getElementById("form1");
var firstForm = document.forms[0]; //取得頁面中的第一個表單
var myForm = document.forms['form2']; //取得頁面中名稱為“form2”的表單
提交表單
用戶單擊提交按鈕或圖像按鈕時,就會提交表單。使用input
或button
都可以定義提交按鈕,只要將其type
特性的值設置為submit
即可,圖像按鈕則是通過將input
的type
特性值設置為image
來定義。
<!--通過提交按鈕-->
<input type="submit" value="Submit">
<!--自定義提交按鈕-->
<button type="submit">Submit</button>
<!--圖像按鈕-->
<input type="image" value="Submit">
只要表單中存在上面列出的任何一種按鈕,那么在相應表單控件擁有焦點的情況下,按回車鍵就可以提交該表單。textarea
是一個例外,在文本區中回車會換行。如果表單里沒有提交按鈕,按回車鍵不會提交表單。
以這種方式提交表單時,瀏覽器會在將請求發送給服務器之前觸發submit
事件。這樣,我們就有機會驗證表單數據,并據以決定是否允許表單提交。阻止這個事件的默認行為就可以取消表單提交。
var form = document.getElementById("myForm");
EventUtil.addHandler(form, "submit", function(event) {
//取得事件對象
event = EventUtil.getEvent(event);
//阻止默認事件(阻止表單提交)
EventUtil.preventDefault(event);
});
在JS中,以編程方式調用submit()
方法也可以提交表單。而且,這種方式無需表單包含提交按鈕,任何時候都可以正常提交表單。
var form = document.getElementById("myForm");
//提交表單
form.submit();
提交表單時可能出現的最大問題,就是重復提交表單。解決這一問題的辦法有兩個:在第一次提交表單后就禁用提交按鈕,或者利用onsubmit
事件處理程序取消后續的表單提交操作。
重置表單
在用戶單擊重置按鈕時,表單會被重置。使用type
特性值為reset
的input
或button
都可以創建重置按鈕。
<!--通用重置按鈕-->
<input type="reset" value="Reset">
<!--自定義重置按鈕-->
<button type="reset">Reset</button>
在重置表單時,所有表單字段都會恢復到頁面剛加載完畢時的初始值。如果某個字段的初始值為空,就會恢復為空;而帶有默認值的字段,也會恢復為默認值。
用戶單擊重置按鈕重置表單時,會觸發reset
事件。
var form = document.getElementById("myForm");
EventUtil.addHandler(form, "reset", function(event) {
//取得事件對象
event = EventUtil.getEvent(event);
//阻止表單重置
EventUtil.preventDefault(event);
});
也可以通過JS來重置表單:
var form = document.getElementById('form');
form.reset();
與調用submit()
方法不同,調用reset()
方法會像單擊重置按鈕一樣觸發reset
事件。
表單字段
可以使用原生DOM方法訪問表單元素,此外,每個表單都有elements
屬性,該屬性是表單中所有元素的集合。這個elements
集合是一個有序列表,其中包含著表單中所有的字段??梢酝ㄟ^name
屬性或索引來訪問這些字段。
var form = document.getElementById('form');
var field1 = form.elements[0]; //取得表單中的第一個字段
var field2 = form.elements['user']; //取得名為“user”的字段
var fieldCount = form.elements.length; //取得表單中包含的字段的數量
如果有多個控件都在使用一個name
,那么就會返回以該name
命名的一個NodeList
。
1.共有的表單字段屬性
除了<fieldset>
元素外,所有表單字段都有一組相同的屬性。共有屬性:
-
disabled
:布爾值,表示當前字段是否被禁用。 -
form
:指向當前字段所屬表單的指針;只讀。 -
name
:當前字段的名稱。 -
readOnly
:布爾值,表示當前字段是否只讀。 -
tabIndex
:表示當前字段的切換(tab
)序號。 -
type
:當前字段的類型,如checkbox
。 -
value
:當前字段將被提交給服務器的值。對文件字段來說,這個屬性是只讀的,包含著文件在計算機中的路徑。
除了form
屬性外,可以通過JS動態修改其他任何屬性。
var form = document.getElementById("myForm");
var field = form.elements[0];
//修改 value 屬性
field.value = "Another value";
//檢查 form 屬性的值
alert(field.form === form); //true
//把焦點設置到當前字段
field.focus();
//禁用當前字段
field.disabled = true;
//修改 type 屬性(不推薦,但對<input>來說是可行的)
field.type = "checkbox";
能夠動態修改表單字段屬性,意味著我們可以在任何時候,以任何方式來動態操作表單。如避免多次提交表單。
//避免多次提交表單
EventUtil.addHandler(form, "submit", function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
//取得提交按鈕
var btn = target.elements["submit-btn"];
//禁用它
btn.disabled = true;
});
注意,不能通過onclick
事件處理程序來實現這個功能,原 因是不同瀏覽器之間存在“時差”;有的瀏覽器會在觸發表單的submit
事件之前觸發click
事件,而有的瀏覽器則相反。因此,最好是通過submit
事件來禁用提交按鈕。不過,這種方式不適合表單中不包含提交按鈕的情況;只有在包含提交按鈕的情況下,才有可能觸發表單的submit
事件。
除了<fieldset>
,所有表單字段都有type
屬性。對于input
元素,這個值等于HTML特性type
的值。對于其他元素,這個type
屬性的值如下表所列。
此外,input
和button
元素的type
屬性是可以動態修改的,而select
元素的type
屬性則是只讀的。
2.共有的表單字段方法
每個表單字段都有兩個方法:focus()
和blur()
。focus()
方法用于將瀏覽器的焦點設置到表單字段,即激活表單字段,使其可以響應鍵盤事件。例如,在頁面加載完畢后,將焦點轉移到表單中的第一個字段。為此,可以偵聽頁面的load
事件,并在該事件發生時在表單的第一個字段上調用focus()
方法。
EventUtil.addHandler(window, "load", function(event) {
document.forms[0].elements[0].focus();
});
要注意的是,如果第一個表單字段是一個<input>
元素,且其type
特性的值為hidden
,那么以上代碼會導致錯誤。另外,如果使用CSS的display
和visibility
屬性隱藏了該字段,同樣也會導致錯誤。
HTML5為表單字段新增了一個autofocus
屬性。只要設置這個屬性,不用JS就能自動把焦點移動到相應字段。
<input type="text" autofocus>
為了保證前面的代碼在設置autofocus
的瀏覽器中正常運行,必須先檢測是否設置了該屬性,如果設置了,就不用再調用focus()
了。
EventUtil.addHandler(window, "load", function(event) {
var element = document.forms[0].elements[0];
if (element.autofocus !== true) {
element.focus();
console.log("JS focus");
}
});
在默認情況下,只有表單字段可以獲得焦點。對于其他元素而言,如果先將其tabIndex
屬性設置為-1,然后再調用focus()
方法,也可以讓這些元素獲得焦點。
blur()
方法的作用是從元素中移走焦點。在調用blur()
方法時, 并不會把焦點轉移到某個特定的元素上;僅僅是將焦點從調用這個方法的元素上面移走而已。
document.forms[0].elements[0].blur();
3.共有的表單字段事件
除了支持鼠標、鍵盤、更改和HTML事件之外,所有表單字段都支持下列3個事件。
-
blur
:當前字段失去焦點時觸發。 -
change
:對于<input>
和<textarea>
元素,在它們失去焦點且value
值改變時觸發;對于<select>
元素,在其選項改變時觸發。 -
focus
:當前字段獲得焦點時觸發。
當用戶改變了當前字段的焦點,或者我們調用了blur()
或focus()
方法時,都可以觸發blur
和focus
事件。這兩個事件在所有表單字段中都是相同的。但是,change
事件在不同表單控件中觸發的次數會有所不同。對于<input>
和<textarea>
元素,當它們從獲得焦點到失去焦點且value
值改變時,才會觸發change
事件。對于<select>
元素,只要用戶選擇了不同的選項,就會觸發change
事件;換句話說,不失去焦點也會觸發change
事件。
通常,可以使用focus
和blur
事件來以某種方式改變用戶界面。而change
事件則經常用于驗證用戶在字段中輸入的數據??梢岳?code>blur事件恢復文本框的背景顏色,利用change
事件在用戶輸入了非數值字符時再次修改背景顏色。
var textbox = document.forms[0].elements[0];
EventUtil.addHandler(textbox, "focus", function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
if (target.style.backgroundColor != "red") {
target.style.backgroundColor = "yellow";
}
});
EventUtil.addHandler(textbox, "blur", function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
if (/[^\d]/.test(target.value)){
target.style.backgroundColor = "red";
} else {
target.style.backgroundColor = "";
}
});
EventUtil.addHandler(textbox, "change", function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
if (/[^\d]/.test(target.value)) {
target.style.backgroundColor = "red";
} else {
target.style.backgroundColor = "";
}
});
文本框腳本
在HTML中,有兩種方式來表現文本框:一種是使用<input>
元素的單行文本框,另一種是使用<textarea>
的多行文本框。
要表現文本框,必須將<input>
元素的type
特性設置為text
。而通過設置size
特性,可以指定文本框中能夠顯示的字符數。通過value
特性,可以設置文本框的初始值,而maxlength
特性則用于指定文本框可以接受的最大字符數。
<textarea>
元素則始終會呈現為一個多行文本框。要指定文本框的大小,可以使用rows
和cols
特性。其中,rows
特性指定的是文本框的字符行數,而cols
特性指定的是文本框的字符列數 。<textarea>
的初始值必須要放在<textarea>
和</textarea>
之間。不能在HTML中給<textarea>
指定最大字符數。
<input type="text" size="25" maxlength="50" value="initial value">
<textarea rows="25" cols="5">initial value</textarea>
這兩種文本框都會將用戶輸入的內容保存在value
屬性中??梢酝ㄟ^這個屬性讀取和設置文本框的值。
var textbox = document.forms[0].elements["textbox1"];
alert(textbox.value);
textbox.value = "Some new value";
選擇文本
這兩種文本框都支持select()
方法,這個方法用于選擇文本框中的所有文本。在調用select()
方法時,大多數瀏覽器都會將焦點設置到文本框中。這個方法不接受參數,可以在任何時候被調用。
var textbox = document.forms[0].elements["textbox1"];
textbox.select();
1.選擇(select)事件
與select()
方法對應的,是一個select
事件。在選擇了文本框中的文本時,就會觸發select
事件。在調用select()
方法時也會觸發select
事件。
var textbox = document.forms[0].elements["textbox1"];
EventUtil.addHandler(textbox, "select", function(event){
var alert("Text selected" + textbox.value);
});
2.取得選擇的文本
雖然通過select
事件我們可以知道用戶什么時候選擇了文本,但仍然不知道用戶選擇了什么文本。
HTML5添加了兩個屬性:selectionStart
和selectionEnd
。這兩個屬性中保存的是基于0的數值,表示所選擇文本的范圍。因此,要取得用戶在文本框中選擇的文本,可以使用如下代碼。
function getSelectedText(textbox) {
return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd);
}
3.選擇部分文本
除select()
方法之外,所有文本框都有一個setSelectionRange()
方法。這個方法接收兩個參數:要選擇的第一個字符的索引和要選擇的最后一個字符之后的字符的索引。
textbox.value = "Hello world!"
//選擇所有文本
textbox.setSelectionRange(0, textbox.value.length); //"Hello world!"
//選擇前 3 個字符
textbox.setSelectionRange(0, 3); //"Hel"
//選擇第 4 到第 6 個字符
textbox.setSelectionRange(4, 7); //"o w"
要看到選擇的文本,必須在調用setSelectionRange()
之前或之后立即將焦點設置到文本框。
自動切換焦點
通常,在自動切換焦點之前,必須知道用戶已經輸入了既定長度的數據。例如,美國的電話號碼通常會分為三部分:區號、局號和另外4位數字。為取得完整的電話號碼,很多網頁中都會提供3個文本框:
<input type="text" name="tel1" id="txtTel1" maxlength="3">
<input type="text" name="tel2" id="txtTel2" maxlength="3">
<input type="text" name="tel3" id="txtTel3" maxlength="4">
為增強易用性,同時加快數據輸入,可以在前一個文本框中的字符達到最大數量后,自動將焦點切換到下一個文本框。
(function(){
function tabForward(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
if (target.value.length == target.maxLength){
var form = target.form;
for (var i=0, len=form.elements.length; i < len; i++) {
if (form.elements[i] == target) {
if (form.elements[i+1]){
form.elements[i+1].focus();
}
return;
}
}
}
}
var textbox1 = document.getElementById("txtTel1");
var textbox2 = document.getElementById("txtTel2");
var textbox3 = document.getElementById("txtTel3");
EventUtil.addHandler(textbox1, "keyup", tabForward);
EventUtil.addHandler(textbox2, "keyup", tabForward);
EventUtil.addHandler(textbox3, "keyup", tabForward);
})();
HTML5約束驗證API
為了在將表單提交到服務器之前驗證數據,HTML5新增了一些功能。有了這些功能,即便JS被禁用或者由于種種原因未能加載,也可以確?;镜尿炞C。
只有在某些情況下表單字段才能進行自動驗證。具體來說,就是要在HTML標記中為特定的字段指定一些約束,然后瀏覽器才會自動執行表單驗證。
1.必填字段
第一種情況是在表單字段中指定了required
屬性:
<input type="text" name="username" required>
任何標注有required
的字段,在提交表單時都不能空著。這個屬性適用于<input>
、<textarea>
和<select>
字段。在JS中,通過對應的required
屬性,可以檢查某個表單字段是否為必填字段。
var isUsernameRequired = document.forms[0].elements["username"].required;
另外,使用下面代碼可以測試瀏覽器是否支持required
屬性。
var isRequiredSupported = "required" in document.createElement("input");
2.其他輸入類型
HTML5為<input>
元素的type
屬性又增加了幾個值。這些新的類型不僅能反映數據類型的信息,而且還能提供一些默認的驗證功能。
<input type="email" name="email">
<input type="url" name="homepage">
要檢測瀏覽器是否支持這些新類型,可以在JS創建一個<input>
元素,然后將type
屬性設為新類型,最后再檢測這個屬性的值。不支持它們的瀏覽器會自動將未知的值設置為text
,支持的瀏覽器會返回正確的值。
var input = document.createElement("input");
input.type = "email";
var isEmailSupported = (input.type == "email");
如果不給<input>
元素設置required
屬性,那么空文本框也會驗證通過。另一方面,設置特定的輸入類型并不能阻止用戶輸入無效的值,只是應用某些默認的驗證而已。
3.數值范圍
對數值類型的輸入元素,可以指定min
屬性、max
屬性和step
屬性。
<input type="number" min="0" max="100" step="5" name="count">
以上這些屬性在JS中都能通過對應的元素訪問。
4.輸入模式
HTML5為文本字段新增了pattern
屬性。這個屬性的值是一個正則表達式,用于匹配文本框中的值。
//只允許在文本字段中輸入數值
<input type="text" pattern="\d+" name="count">
指定pattern
也不能阻止用戶輸入無效的文本。這個模式應用給值,瀏覽器來判斷值是有效,還是無效。在 JS中可以通過pattern
屬性訪問模式。
var pattern = document.forms[0].elements["count"].pattern;
使用以下代碼可以檢測瀏覽器是否支持pattern
屬性。
var isPatternSupported = "pattern" in document.createElement("input");
5.檢測有效性
使用checkValidity()
方法可以檢測表單中的某個字段是否有效。所有表單字段都有個方法,如果字段的值有效,這個方法返回true
,否則返回false
。換句話說,必填字段中如果沒有值就是無效的,而字段中的值與pattern
屬性不匹配也是無效的。
if (document.forms[0].elements[0].checkValidity()) {
//字段有效,繼續
} else {
//字段無效
}
要檢測整個表單是否有效,可以在表單自身調用checkValidity()
方法。如果所有表單字段都有效,這個方法返回true
;即使有一個字段無效,這個方法也會返回false
。
if(document.forms[0].checkValidity()) {
//表單有效,繼續
} else {
//表單無效
}
validity
屬性會告訴你為什么字段有效或無效。這個對象中包含一系列屬性,每個屬性會返回一個布爾值。
-
customError
:如果設置了setCustomValidity()
,則為true
,否則返回false
。 -
patternMismatch
:如果值與指定的pattern
屬性不匹配,返回true
。 -
rangeOverflow
:如果值比max
值大,返回true
。 -
rangeUnderflow
:如果值比min
值小,返回true
。 -
stepMisMatch
:如果min
和max
之間的步長值不合理,返回true
。 -
tooLong
:如果值的長度超過了maxlength
屬性指定的長度,返回true
。有的瀏覽器會自動約束字符數量,因此這個值可能永遠都返回false
。 -
typeMismatch
:如果值不是mail
或url
要求的格式,返回true
。 -
valid
:如果這里的其他屬性都是false
,返回true
。checkValidity()
也要求相同的值。 -
valueMissing
:如果標注為required
的字段中沒有值,返回true
。
if (input.validity && !input.validity.valid) {
if (input.validity.valueMissing) {
alert("Please specify a value.")
} else if (input.validity.typeMismatch) {
alert("Please enter an email address.");
} else {
alert("Value is invalid.");
}
}
6.禁用驗證
通過設置novalidate
屬性,可以告訴表單不進行驗證。
<form method="post" action="signup.php" novalidate>
<!--這里插入表單元素-->
</form>
在JS中使用noValidate
屬性可以取得或設置這個值,如果這個屬性存在,值為true
,如果不存在,值為false
。
document.forms[0].noValidate = true; //禁用驗證
如果一個表單中有多個提交按鈕,為了指定點擊某個提交按鈕不必驗證表單,可以在相應的按鈕上添加formnovalidate
屬性。
<form method="post" action="foo.php">
<!--這里插入表單元素-->
<input type="submit" value="Regular Submit">
<input type="submit" formnovalidate name="btnNoValidate" value="Non-validating Submit">
</form>
使用JS也可以設置這個屬性。
//禁用驗證
document.forms[0].elements["btnNoValidate"].formNoValidate=true;
選擇框腳本
選擇框是通過<select>
和<option>
元素創建的。為了方便與這個控件交互,除了所有表單字段共有的屬性和方法外,HTMLSelectElement
類型還提供了下列屬性和方法。
-
add(newOption, relOption)
:向控件中插入新<option>
元素,其位置在相關項(relOption
)之前。 -
multiple
:布爾值,表示是否允許多項選擇;等價于HTML中的multiple
特性。 -
options
:控件中所有<option>
元素的HTMLCollection
。 -
remove(index)
:移除給定位置的選項。 -
selectedIndex
:基于0的選中項的索引,如果沒有選中項,則值為-1。對于支持多選的控件,只保存選中項中第一項的索引。 -
size
:選擇框中可見的行數;等價于HTML中的size
特性。
選擇框的type
屬性不是select-one
,就是select-multiple
,這取決于HTML代碼中有沒有multiple
特性。選擇框的value
屬性由當前選中項決定,相應規則如下。
- 如果沒有選中的項,則選擇框的
value
屬性保存空字符串。 - 如果有一個選中項,而且該項的
value
特性已經在HTML中指定,則選擇框的value
屬性等于選中項的value
特性。即使value
特性的值是空字符串,也同樣遵循此條規則。 - 如果有一個選中項,但該項的
value
特性在HTML中未指定,則選擇框的value
屬性等于該項的文本。 - 如果有多個選中項,則選擇框的
value
屬性將依據前兩條規則取得第一個選中項的值。
<select name="location" id="selLocation">
<option value="Sunnyvale,CA">Sunnyvale</option>
<option value="">China</option>
<option>Australia</option>
</select>
如果用戶選擇了其中第一項,則選擇框的值就是Sunnyvale,CA
。如果文本為China
的選項被選中,則選擇框的值就是一個空字符串,因為其value
特性是空的。如果選擇了最后一項,那么由于<option>
中沒有指定value
特性,則選擇框的值就是Australia
。
在DOM中,每個<option>
元素都有一個HTMLOptionElement
對象表示。HTMLOptionElement
對象有下列屬性:
-
index
:當前選項在options
集合中的索引。 -
label
:當前選項的標簽;等價于HTML中的label
特性。 -
selected
:布爾值,表示當前選項是否被選中。將這個屬性設置為true
可以選中當前選項。 -
text
:選項的文本。 -
value
:選項的值(等價于HTML中的value
特性)。
雖然可以使用常規的DOM功能來訪問這些信息,但使用選項屬性更方便。
var selectbox = document.forms[0].elements["location"];
//不推薦
var text = selectbox.options[0].firstChild.nodeValue; //選項的文本
var value = selectbox.options[0].getAttribute("value"); //選項的值
//推薦
var text = selectbox.options[0].text; //選項的文本
var value = selectbox.options[0].value; //選項的值
選擇框的change
事件與其他表單字段的change
事件觸發的條件不一樣。其他表單字段的change
事件是在值被修改且焦點離開當前字段時觸發,而選擇框的change
事件只要選中了選項就會觸發。
選擇選項
對于只允許選擇一項的選擇框,訪問選中項的最簡單方式,就是使用選擇框的selectedIndex
屬性。
const selectedOption = selectbox.options[selectbox.selectedIndex];
取得選中項之后,可以像下面這樣顯示該選項的信息:
const selectedIndex = selectbox.selectedIndex;
const selectedOption = selectbox.options[selectedIndex];
console.log("Selected index: " + selectedIndex + "\n Selected text: " +
selectedOption.text + "\n Selected value: " + selectedOption.value);
對于可以選擇多項的選擇框,selectedfIndex
屬性就好像只允許選擇一項一樣。設置selectedIndex
會導致取消以前的所有選項并選擇指定的那一項,而讀取selectedIndex
則只會返回選中項中第一項的索引值。
另一種選擇選項的方式,就是取得對某一項的引用,然后將其selected
屬性設置為true
。
selectbox.options[0].selected = true;
與selectedIndex
不同,在允許多選的選擇框中設置選項的selected
屬性,不會取消對其他選中項的選擇,因而可以動態選中任意多個項。但是,如果是在單選選擇框中,修改某個選項的selected
屬性則會取消對其他選項的選擇。需要注意的是,將selected
屬性設置為false
對單選選擇框沒有影響。
實際上,selected
屬性的作用主要是確定用戶選擇了選擇框中的哪一項。要取得所有選中的項,可以循環遍歷選項集合,然后測試每個選項的selected
屬性。
function getSelectedOptions(selectbox) {
var result = new Array();
var option = null;
for (var i = 0, len=selectbox.options.length; i < len; i++) {
option = selectbox.options[i];
if (option.selected) {
result.push(option);
}
}
return result;
}
// 取得所有選中項
var selectbox = document.getElementById('selLocation');
var selectedOptions = getSelectedOptions(selectbox);
var message = '';
for(var i = 0, len = selectedOptions.length; i < len; i++) {
message += 'selected index:' + selectedOptions[i].index +
'\nselected text:' + selectedOptions[i].text + '\nselected value:' + selectedOptions[i].value + '\n\n';
}
console.log(message);
這個函數可以返回給定選擇框中選中項的數組。
添加選項
可以使用JS動態創建選項,并將它們添加到選擇框中。添加選項的方式有很多,第一種方式就是使用DOM方法。
var newOption = document.createElement("option"); newOption.appendChild(document.createTextNode("Option text"));
newOption.setAttribute("value", "Option value");
selectbox.appendChild(newOption);
第二種方式是使用Option
構造函數來創建新選項,這個構造函數是DOM出現之前就有的,一直遺留到現在。Option
構造函數接受兩個參數:文本(text
)和值(value
);第二個參數可選。 雖然這個構造函數會創建一個Object
的實例,但兼容DOM的瀏覽器會返回一個<option>
元素。在這種情況下,我們仍然可以使用appendChild()
將新選項添加到選擇框中。
var newOption = new Option("Option text", "Option value");
selectbox.appendChild(newOption); //在IE8及之前版本中有問題
第三種添加新選項的方式是使用選擇框的add()
方法。DOM規定這個方法接受兩個參數:要添加的新選項和將位于新選項之后的選項。如果想在列表的最后添加一個選項,應該將第二個參數設置為null
。在IE對add()
方法的實現中,第二個參數是可選的,而且如果指定,該參數必須是新選項之后選項的索引。兼容DOM的瀏覽器要求必須指定第二個參數,因此要想編寫跨瀏覽器的代碼,就不能只傳入一個參數。這時候,為第二個參數傳入undefined
,就可以在所有瀏覽器中都將新選項插入到列表最后了。
var newOption = new Option("Option text", "Option value");
selectbox.add(newOption, undefined); //最佳方案
移除選項
移除選項的方式有很多種。首先,可以使用DOM的removeChild()
方法, 為其傳入要移除的選項。
selectbox.removeChild(selectbox.options[0]); //移除第一個選項
其次,可以使用選擇框的remove()
方法。這個方法接受一個參數,即要移除選項的索引。
selectbox.remove(0); //移除第一個選項
最后一種方式,就是將相應選項設置為null
。這種方式也是DOM出現之前瀏覽器的遺留機制。
selectbox.options[0] = null; //移除第一個選項
要清除選擇框中所有的項,需要迭代所有選項并逐個移除它們。
function clearSelectbox(selectbox) {
for(var i=0,len=selectbox.options.length; i<len; i++) {
selectbox.remove(i);
}
}
移動和重排選項
使用DOM的appendChild()
方法可以將第一個選擇框中的選項直接移動到第二個選擇框中。如果為appendChild()
方法傳入一個文檔中已有的元素,那么就會先從該元素的父節點中移除它,再把它添加到指定的位置。
var selectbox1 = document.getElementById("selLocations1");
var selectbox2 = document.getElementById("selLocations2");
selectbox2.appendChild(selectbox1.options[0]);
移動選項與移除選項有一個共同之處,即會重置每一個選項的index
屬性。
將選擇框中的某一項移動到特定位置,最合適的DOM方法就是insertBefore()
;appendChild()
方法只適用于將選項添加到選擇框的最后。
var optionToMove = selectbox.options[1];
selectbox.insertBefore(optionToMove,selectbox.options[optionToMove.index-1]);
表單序列化
在JS中,可以利用表單字段的type
屬性,連同name
和value
屬性一起實現對表單的序列化。在編寫代碼之前, 有必須先搞清楚在表單提交期間,瀏覽器是怎樣將數據發送給服務器的。
- 對表單字段的名稱和值進行URL編碼,使用和號(&)分隔。
- 不發送禁用的表單字段。
- 只發送勾選的復選框和單選按鈕。
- 不發送
type
為reset
和button
的按鈕。 - 多選選擇框中的每個選中的值單獨一個條目。
- 在單擊提交按鈕提交表單的情況下,也會發送提交按鈕;否則,不發送提交按鈕。也包括
type
為image
的<input>
元素。 -
<select>
元素的值,就是選中的<option>
元素的value
特性的值。如果<option>
元素沒有value
特性,則是<option>
元素的文本值。
在表單序列化過程中,一般不包含任何按鈕字段,因為結果字符串很可能是通過其他方式提交的。以下就是實現表單序列化的代碼。
function serialize(form) {
var parts = [], field = null, i, len, j, optLen, option, optValue;
for (i=0, len = form.elements.length; i < len; i++) {
field = form.elements[i];
switch(field.type) {
case "select-one":
case "select-multiple":
if (field.name.length) {
for (j=0, optLen = field.options.length; j < optLen; j++) {
option = field.options[j];
if (option.selected) {
optValue = (option.hasAttribute("value") ?
option.value : option.text);
parts.push(encodeURIComponent(field.name) + "=" +
encodeURIComponent(optValue));
}
}
}
break;
case undefined: //字段集
case "file": //文件輸入
case "submit": //提交按鈕
case "reset": //重置按鈕
case "button": //自定義按鈕
break;
case "radio": //單選按鈕
case "checkbox": //復選框
if (!field.checked) {
break;
}
/* 執行默認操作 */
default:
//不包含沒有名字的表單字段
if (field.name.length) {
parts.push(encodeURIComponent(field.name) + "=" +
encodeURIComponent(field.value));
}
}
}
return parts.join("&");
}
序列化過程中最麻煩的是<select>
元素,它可能是單選框也可能是多選框。為此需要遍歷控件中的每一個選項并在相應選項被選中的情況下向數組中添加一個值。在找到一個選中項之后,需要確定使用什么值,如果不存在value
或值為空字符串,都要使用選項的文本來代替。
對于單選按鈕和復選框,要檢查其checked
屬性是否為false
,如果是則退出switch
語句。如果checked
屬性為true
,則繼續執行default
語句,即將當前字段的名稱和值進行編碼,然后添加到parts
數組中。
最后,serialize()
函數會以查詢字符串的格式輸出序列化之后的字符串。