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事件则经常用于验证用户在字段中输入的数据。可以利用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被禁用或者由于种种原因未能加载,也可以确保基本的验证。
只有在某些情况下表单字段才能进行自动验证。具体来说,就是要在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,返回truecheckValidity()也要求相同的值。
  • 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()函数会以查询字符串的格式输出序列化之后的字符串。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容

  • 14.1 表单的基础知识 表单由 元素来表示,继承自HTMLElement类型,除具有HTML元素相同的默认属性外...
    Elevens_regret阅读 337评论 0 0
  • 本人做php的,最近发现JS真的是博大精深啊,比PHP难.在HTML中,表单是由form元素来表示的,但是在jav...
    linfree阅读 2,040评论 3 17
  • 本章内容 理解表单 文本框验证与交互 使用其他表单控制 14.1 表单的基础知识 通过document.forms...
    闷油瓶小张阅读 349评论 0 0
  • HTML表单 在HTML中,表单是 ... 之间元素的集合,它们允许访问者输入文本、选择选项、操作对象等等,然后将...
    兰山小亭阅读 3,362评论 2 14
  • 等待是一种熬, 时而像烈焰,像慢火,时而像微风,像细雨。 等待是一面镜, 从里而外来回审视 等待是回归, 回归内心...
    他说什么阅读 220评论 0 0