14.1 表单的基础知识
表单由<form>元素来表示,继承自HTMLElement类型,除具有HTML元素相同的默认属性外,还具有以下属性和方法:
action属性,接受请求的URL;
elements属性,表单中所有控件的合集;
length属性,表单中控件的数量;
method属性,要发送的HTTP请求类型,通常是get或post;
name属性,表单的名称;
reset()方法,将表单域重置为默认值;
submit()方法,提交表单。
除使用基本的DOM获取方法获取表单外,document.forms属性可以取得页面中所有的表单,可以通过索引或name值来取得特定表单。
14.1.1 提交表单
单机提交按钮或图像按钮时会提交表单,type属性为"submit"的<input>标签和<button>标签会生成提交按钮,type属性为"image"的<input>标签会生成图像按钮。
<button type="submit">提交</button>
<input type="submit" value="提交">
<input type="image" src="tijiao.jpg">
在具有这三种控件的表单获得焦点时,按下回车键就会提交表单,浏览器在提交表单时会触发submit事件,可以在此验证表单,并决定是否提交,阻止事件的默认行为就可以取消表单的提交。submit()方法也可以提交表单,但使用此方法提交表单不会触发submit事件。
为防止表单的重复提交,在第一次提交表单后,就应该禁用提交按钮,或者利用onsubmit事件处理程序取消后续的表单提交操作。
14.1.2 重置表单
单机重置按钮时,表单的所有控件都会被重置为默认值,type属性为"reset"属性的<input>标签和<button>标签会生成重置按钮。
<button type="reset">重置</button>
<input type="reset" value="重置">
单击重置按钮时,会触发reset事件,阻止事件的默认行为可以取消表单的重置,reset()方法也可以重置表单,调用reset()方法时,也会触发reset事件。
14.1.3 表单字段
每个表单都有elements属性,该属性是表单中所有表单元素的集合。可以按照每个控件元素出现的顺序或name属性来获取它们。
var f1= document.forms[0].elements[0];
var f2= document.forms[0].elements["first"];
使用name方式获取表单元素时,如果有多个表单使用同一个name(单选按钮),则返回一个以该name命名的NodeList。使用索引方式获取表单元素则只会返回第一个匹配的表单元素。
<form>
<input type="radio" name="first" value="red">
<input type="radio" name="first" value="blue">
<input type="radio" name="first" value="green">
</form>
var f1= document.forms[0].elements[0];
var f2= document.forms[0].elements["first"];
console.log(f1 === f2[0]); // true
表单字段的共有属性:
disabled属性,布尔值,表示当前表单是否禁用;
form属性,指向当前字段所属的表单;
name属性,当前字段名称;
readOnly属性,布尔值,表示当前字段是否只读;
tabIndex属性,表示当前字段的切换序号;
type属性,当前字段的类型;
value属性,当前字段被提交给服务器的值,文件字段中是只读的,表示文件在计算机中的路径。
表单字段共有的方法:
focus()方法,将浏览器焦点设置到当前字段。
blur()方法,将浏览器焦点从表单控件中移除。
HTML5新添加autofocus属性,设置了这个属性的表单控件在进入页面时会自动获得焦点。
表单字段共有的事件:
blur事件,当前字段失去焦点时触发。
change事件,<input>元素和<textarea>元素失去焦点且value的值发生变化时触发,<select>元素的选项发生改变时触发。
focus事件,当前字段获得焦点时触发。
调用focus()和blur()方法同样会触发focus和blur事件。
14.2 文本框脚本
type属性为"text"的<input>元素表示单行文本框,<textarea>元素表示多行文本框。size特性指定文本框中能够显示的字符数。value特性可以设置文本框的初始值(<textarea>元素的初始值在标签中间)。maxlength特性用于指定文本框可以接受的最大字符数。 用户数的输入内容都保存在表单字段的value属性中。要更改value值时,直接使用value属性,不要使用DOM去修改文本框的值。
14.2.1 选择文本
select()方法,可以选中文本框中的所有文本,在文本框获得焦点时,选择其所有文本,可以方便一次性修改。
在选择文本框中的文本时,就会触发select事件,在调用select()方法时,也会触发select事件。selectionStart和selectionEnd两个属性分别保存所选文本的开头和结尾偏移量。使用下列方法可以获取选择的文本:
<input type="text" value="hello world!">
var f1= document.forms[0].elements[0];
EventUtil.addHandler(f1,"select",function (event) {
console.log(f1.value.substring(f1.selectionStart,f1.selectionEnd));
});
setSelectionRange()方法可以选择文本框的一部分文本,接收两个参数,要选择的第一个字符的索引和要选择的最后一个字符之后的字符的索引。要看到选择的文本,必须在之前或之后立即将焦点设置到文本框上。
14.2.2 过滤输入
只允许用户输入数值:
EventUtil.addHandler(f1,"keypress",function (event) {
event = EventUtil.getEvent(event);
var charCode = EventUtil.getCharCode(event);
if(!/\d/.test(String.fromCharCode(charCode))&&charCode>9&&!event.ctrlKey){
EventUtil.preventDefault(event);
}
});
通过/\d/测试值是否为数字,在Firefox中,所有非字符键触发的keypress事件对应的字符编码为0,早期Safari版本为8,所以不能屏蔽小于9的按键,因为此代码还会屏蔽Ctrl+C,Ctrl+V之类的组合件,所以还要检测是否按下Ctrl键。
剪贴板事件:
beforecopy事件,在发生复制操作前触发;
copy事件,发生复制操作时触发;
beforecut事件,在发生剪切操作前触发;
cut事件,发生剪切操作时触发;
beforepaste事件,在发生粘贴操作前触发;
paste事件,发生粘贴操作时触发;
发生剪贴板事件时,可以使用clipboardDate对象访问剪贴板中的数据,在IE中是window对象的属性,在其他浏览器中是事件对象的属性。此对象有3个方法:
getData(),从剪贴板中取得数据,接受一个参数,一般为"text";只有在onpaste事件处理程序中才可以使用此方法。
setData(),设置剪贴板中的数据,接受两个参数,第一个为"text/plain",在IE中为"text",第二个是要放在剪贴板中的数据,成功设置剪贴板中的数据后,返回true,否则返回false。
修改复制文本框中内容的方法:
var f1= document.forms[0].elements[0];
var str ="";
EventUtil.addHandler(f1,"select",function (event) {
event = EventUtil.getEvent(event);
str = f1.value.substring(f1.selectionStart,f1.selectionEnd);
});
EventUtil.addHandler(f1,"copy",function (event) {
event = EventUtil.getEvent(event);
str+="abc";
EventUtil.setClipboardText(event,str);
EventUtil.preventDefault(event);
});
EventUtil.addHandler(f1,"paste",function (event) {
event = EventUtil.getEvent(event);
var a = EventUtil.getClipboardText(event);
EventUtil.setClipboardText(event,a);
});
14.2.3 自动切换焦点
为增强易用性,同时加快数据输入,可以在前一个文本框中的字符达到最大数量后,自动将焦点切换到下一个文本框。
<form>
<input type="text" value="" maxlength="3">
<input type="text" value="" maxlength="3">
<input type="text" value="" maxlength="3">
</form>
function tabInput(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();
form.elements[i+1].select();
}
return;
}
}
}
}
var f0 = document.forms[0].elements[0];
var f1 = document.forms[0].elements[1];
var f2 = document.forms[0].elements[2];
EventUtil.addHandler(f0,"keyup",tabInput);
EventUtil.addHandler(f1,"keyup",tabInput);
EventUtil.addHandler(f2,"keyup",tabInput);
14.2.4 HTML5约束验证API
required属性,表示必填字段。在JavaScript中检测此属性可以检查此字段是否必填。存在这个属性则为true,不存在则为false。
email,url类型。当type属性为这两个时,浏览器会对内容进行验证,email必须为email值,url必须为url值。注意必须添加required属性,否则空文本也会通过验证。
数值类型:"number"、"range"、"datetime"、"datetime-local"、"date"、"month"、"week"、"time"。这些类型都基于数字。可以指定min和max来表示最小值和最大值。step属性表示每次变化的增量。还有stepUp()和stepDown()两个方法,都接收一个参数,即要加减的数值,默认为1。
pattern属性,一个正则表达式,用于匹配文本框中的值。模式的开头不用加^和&符号,假定已经有了。表示输入的值必须从头到尾都和模式匹配。在JavaScript中检测此属性可以访问匹配模式。
checkValidity()方法,检测表单中某个字段是否有效。所有表单字段都有这个方法,有效则返回true,否则返回false。要检测整个表单是否有效,可以直接在表单自身调用该方法。
validity对象可以告知有效或无效的具体信息。包含以下属性:
customError属性,表示是否设置了setCustomValidity(),设置了返回true,否则返回false;
patternMismatch属性,如果与指定的pattern属性不匹配,则返回true;
rangeOverflow属性,如果值比max大,则返回true;
stepMisMatch属性,如果不是位于min和max之间的由step增量得到的值,则返回true;
toolong属性,如果长度超过maxlength的值,则返回true;
typeMismatch属性,如果不是mail或者url要求的格式,则返回true;
valid属性, 如果这里其他属性都为false,则返回true,与checkValidity()方法相同;
valueMissing属性,如果标注为required字段中没有值,则返回true。
novalidate属性,设置于表单上,表示表单不需要验证。
formnovalidate属性,设置于submit按钮上,表示通过该按钮提交的表单不需要验证。
14.3 选择框脚本
选择框由<select>和<option>组成,具有以下属性和方法:
add()方法,向控件中插入新的<option>元素,接收两个参数,第一个参数为需要插入的元素,第二个参数为参考位置,插入位置在参考位置之前;
multiple属性,布尔值,表示是否允许多选,与HTML中指定的multiple特性相同;
options属性,控件中所有<option>元素的集合;
remove()方法,移除指定选项,传入参数为需要移除的项的索引;
selectedIndex属性,基于0的选中项的索引,如果没有选中项,则为-1,多选控件中只保存选中的第一项的索引;
size属性,选框中可见的行数,与HTML中指定的size特性相同;
type属性,只有两种,单选"select-one"和多选"select-multiple";
value属性,没有选中项时,value属性为空值,选中了一个项时,若HTML中指定了value特性,则为value特性值,若没指定,则为文本值,选中了多个项时,value属性将只取第一个选中项的值。
每个<option>都具有以下属性:
index属性,当前选项在options集合中的索引;
label属性,当前选项的标签;
selected属性,布尔值,表示当前选项是否被选中,设置为true可以选中当前选项;
text属性,选项的文本;
value属性,选项的值。
14.3.1 选择选项
对于单选框,访问选中项的方法就是使用selectedIndex属性。
对于多选框,设置selectedIndex属性会取消之前选中的的项,并选择指定的项,读取selectedIndex属性只会返回第一条选中的项的索引。对于多选框,可以先取得其引用,再对其设置selected属性为true。selected属性不会取消其他选项。
取得多选框中所有的选中项:
function getSelectedOptions(selectbox) {
var result = [];
var option = null;
for(var i=0;i<selectbox.options.length;i++){
option = selectbox.options[i];
if(option.selected){
result.push(option);
}
}
return result;
}
14.3.2 添加选项
第一种方法是使用常规DOM方法appendChild()添加选项。
var newOption = document.createElement("option");
newOption.appendChild(document.createTextNode("text"));
newOption.setAttribute("value","new value");
selectbox.appendChild(newOption);
第二种方法是使用Option构造函数,该构造函数接收两个参数,一个是文本,一个是值。创建实例后可直接用DOM方法appendChild()添加到选框中。
var newOption = new Option("Option text", "Option value");
selectbox.appendChild(newOption);
第三种方法是使用选择框的add()方法,接收两个参数为:要添加的新选项和将要位于新选项之后的选项。将第二个参数设置为undefined,可以直接将选项添加到列表最后。
var newOption = new Option("Option text" , "Option value");
selectbox.add(newOption, undefined);
14.3.3 移除选项
第一种方法是使用常规DOM方法removeChild()移除选项。
selectbox.removeChild(selectbox.options[0]);
第二种方法是使用选择框的remove()方法,接收一个参数,即为要移除选项的索引。
selectbox.remove(0);
第三种方法是直接将对应的选项设置为null。
selectbox.options[0] = null;
14.3.4 移动和重排选项
将一个选择框的选项移动到另一个选择框中,可以直接使用DOM的appendChild()方法,因为appendChild()方法传入的是一个文档中已经存在的元素的话,那么就会现从该元素的父节点将其删除,再将其添加到指定的位置。
重新排序选择框同样也是使用DOM的insertBefore()方法,appendChild()方法只能将某个选项移到最后。
14.4 表单序列化
表单提交的数据:
对表单字段的名称和值进行URL编码,使用&号;
不发送禁用的表单字段;
只发送勾选的复选框和单选按钮;
不发送type为"reset"和"button"的按钮;
多选框中的每个选中值为单独一个条目;
在单击提交按钮时才会发送提交按钮;
<select>元素的值为选中的<option>元素的value值。
表单序列化方法:
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 = "";
if(option.hasAttribute){
optValue = (option.hasAttribute("value") ? option.value : option.text);
}else {
optValue = (option.attributes["value"].specified ? 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(optValue));
}
}
}
return parts.join("&");
}