JS表單腳本

表單基礎知識

在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”的表單

提交表單

用戶單擊提交按鈕或圖像按鈕時,就會提交表單。使用inputbutton都可以定義提交按鈕,只要將其type特性的值設置為submit即可,圖像按鈕則是通過將inputtype特性值設置為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特性值為resetinputbutton都可以創建重置按鈕。

<!--通用重置按鈕-->
<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屬性的值如下表所列。

此外,inputbutton元素的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的displayvisibility屬性隱藏了該字段,同樣也會導致錯誤。
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()方法時,都可以觸發blurfocus事件。這兩個事件在所有表單字段中都是相同的。但是,change事件在不同表單控件中觸發的次數會有所不同。對于<input><textarea>元素,當它們從獲得焦點到失去焦點且value值改變時,才會觸發change事件。對于<select>元素,只要用戶選擇了不同的選項,就會觸發change事件;換句話說,不失去焦點也會觸發change事件。
通常,可以使用focusblur事件來以某種方式改變用戶界面。而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>元素則始終會呈現為一個多行文本框。要指定文本框的大小,可以使用rowscols特性。其中,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添加了兩個屬性:selectionStartselectionEnd。這兩個屬性中保存的是基于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:如果minmax之間的步長值不合理,返回true。
  • tooLong:如果值的長度超過了maxlength屬性指定的長度,返回true。有的瀏覽器會自動約束字符數量,因此這個值可能永遠都返回false。
  • typeMismatch:如果值不是mailurl要求的格式,返回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屬性,連同namevalue屬性一起實現對表單的序列化。在編寫代碼之前, 有必須先搞清楚在表單提交期間,瀏覽器是怎樣將數據發送給服務器的。

  • 對表單字段的名稱和值進行URL編碼,使用和號(&)分隔。
  • 不發送禁用的表單字段。
  • 只發送勾選的復選框和單選按鈕。
  • 不發送typeresetbutton的按鈕。
  • 多選選擇框中的每個選中的值單獨一個條目。
  • 在單擊提交按鈕提交表單的情況下,也會發送提交按鈕;否則,不發送提交按鈕。也包括typeimage<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()函數會以查詢字符串的格式輸出序列化之后的字符串。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 14.1 表單的基礎知識 表單由 元素來表示,繼承自HTMLElement類型,除具有HTML元素相同的默認屬性外...
    Elevens_regret閱讀 378評論 0 0
  • 本人做php的,最近發現JS真的是博大精深啊,比PHP難.在HTML中,表單是由form元素來表示的,但是在jav...
    linfree閱讀 2,207評論 3 17
  • 本章內容 理解表單 文本框驗證與交互 使用其他表單控制 14.1 表單的基礎知識 通過document.forms...
    悶油瓶小張閱讀 368評論 0 0
  • HTML表單 在HTML中,表單是 ... 之間元素的集合,它們允許訪問者輸入文本、選擇選項、操作對象等等,然后將...
    蘭山小亭閱讀 3,439評論 2 14
  • 等待是一種熬, 時而像烈焰,像慢火,時而像微風,像細雨。 等待是一面鏡, 從里而外來回審視 等待是回歸, 回歸內心...
    他說什么閱讀 244評論 0 0