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