第十四章
一、表单的基础知识
在HTML中,表单是由<form>元素来表示的,而在javascript中,表单对应的则是HTMLFormElement类型。HTMLFormElement继承了HTMLElement,因而与其他HTML元素具有相同的默认属性。不过,HTMLFormElement也有它自己下列独有的属性和方法。
取得<form>元素的引用方式有好几种。其中最常见的方式就是将它看成与其他元素一样,并为其添加id特性,然后再像下面这样使用getElementById()方法找到它。
var form=document.getElementById(“form1”);
其次,通过document.forms可以取得页面中所有的表单。在这个集合中,可以通过数值索引域name值来取得特定的表单。如下面的例子:
var firstForm=document.forms[0]; //取得页面中的第一个表单
var myForm=document.forms[“form2”]; //取得页面中名称为“form2”的表单。
1.提交表单
用户单击提交按钮或图像按钮时,就会提交表单。使用<input>或<buttton>都可以定义提交按钮,只要将其type特性的值设置为”submit”即可,而图像按钮则是通过将<input>的type特性值设置为“image”来定义的。因此,只要我们单击以下代码生成的按钮,就可以提交表单。
<!—通过提交按钮-->
<input type=”submit” value=”Submit Form”>
<!—自定义提交按钮-->
<button type=”submit”>Submit Form</button>
<!—图像按钮-->
<input type=”image” src=”graphic.gif”>
只要表单中存在上面列出的任何一种按钮,那么在相应表单控件拥有焦点的情况下,按回车就可以提交该表单。如果表单里没有提交按钮,按回车键不会提交表单。
在调用submit()方法的形式提交表单时,不会触发submit事件,因此要记得在调用此方法之前先验证表单数据。
提交表单时可能出现的最大问题,就是重复提交表单。在第一次提交表单后,如果长时间没有反应,用户可能会变得不耐烦。这个时候,他们也许会反复单击提交按钮。结果往往很麻烦或者会造成错误。解决这一问题的办法有两个:在第一次提交表单后就禁用提交按钮,或者利用onsubmit事件处理程序取消后续的表单提交操作。
2.重置表单
在用户单击重置按钮时,表单会被重置。使用type特性值为“reset”的<input>或<button>都可以创建重置按钮,如下面的例子:
<!—通用重置按钮 –>
<input type=”reset” value=”Reset Form”>
<!—自定义重置按钮-->
<button type=”reset”>Reset Form</button>
这两个按钮都可以用来重置表单。在重置表单时,所有表单字段都会恢复到页面刚加载完毕时的初始值。如果某个字段的初始值为空,就会恢复为空;而带有默认值的字段,也会恢复为默认值。
用户单击重置按钮重置表单时,会触发reset事件。利用这个机会,我们可以在必要时取消重置操作。例如:
var form=document.getElementById(“myForm”);
EventUtil.addHandler(form,”reset”,function(event)){
//取得事件对象
event=EventUtil.getEvent(event);
//阻止表单重置
EventUtil.preventDefault(event);
});
与提交表单一样,也可以通过javascript来重置表单,如下面的例子:
var form=document.getElementById(“myForm”);
//重置表单
form.reset();
与调用submit()方法不同,调用reset()方法会像单击重置按钮一样触发reset事件。
3.表单字段
可以像访问页面中的其他元素一样,使用原生DOM方法访问表单元素。此外,每个表单都有elements属性,该属性是表单中所有表单元素的集合,这个elements集合是一个有序列表,其中包含着表单中的所有字段,例如<input>、<textarea>、<button>和<fieldset>。每个表的字段在elements集合中的顺序,与它们出现在标记中的顺序相同,可以按照位置和name特性来访问它们。
(1)共有的表单字段属性
除了<fieldset>元素之外,所有表单字段都拥有相同的一组属性。由于<input>类型可以表示多种表单字段,因此有些属性只适用于某些字段,但还有一些属性时所有字段共有的。共有的属性如下:
disabled:布尔值,表示当前字段是否被禁用。
form:指向当前字段所属表单的指针;只读。
name:当前字段的名称。
readOnly:布尔值,表示当前字段是否只读。
tabIndex:表示当前字段的切换序号。
type:当前字段的类型,如“checkbox”、“radio”等等。
value:当前字段将被提交给服务器的值。对文件字段来说,这个属性是只读的,包含着文件在计算机中的路径。
除了form属性之外,可以通过javascript动态修改其他任何属性。来看下面的例子:
var form = document.getElementById(“myForm”) ;
var field = form.elements[0] ;
//修改value属性
field.value = “Another value” ;
//检查form属性的值
alert(field.form===form) ; //true
能够动态修改表单字段属性,意味着我们可以在任何时候,以任何方式来动态操作表单。例如,很多用户可能会重复点击表单的提交按钮。在涉及信用卡消费时,这就是个问题:因为会导致费用翻番。最常见的解决方案就是在第一次单击后就禁用提交按钮。只要侦听submit事件,并在该事件发生时禁用提交按钮即可。以下就是一个例子:
//避免多次提交表单
EventUtil.addHandler(form, “submit” , function(event){
event = EventUtil.getEvent(event) ;
var target = EventUtil.getTarget(event) ;
//取得提交按钮
var btn = target.elements[“submit-btn”] ;
//禁用它
btn.disabled = true ;
} ) ;
以上代码为表单的submit事件添加了一个事件处理程序。事件触发之后,代码取得了提交按钮并将其disabled属性设置为true。
(2)共有的表单字段方法
每个表单字段都有两个方法:focus( )和blur( )。其中,focus( )方法用于将浏览器的焦点设置到表单字段,即激活表单字段,使其可以响应键盘事件。blur( )方法的作用是从元素中移走焦点。在调用blur( )方法时,并不会把焦点转移到某个特定的元素上;仅仅是将焦点从调用这个方法的元素上移走而已。语法如下:document.forms[0].elements[0].blur( );
HTML5为表单字段新增了一个autofocus属性。支持这个属性的浏览器中,只要设置这个属性,不用javascript就能自动把焦点移到相应字段。例如“
<input type =”text” autofocus >
(3)共有的表单字段事件
除了支持鼠标、键盘、更改和HTML事件之外,所有表单字段都支持下列3个事件。
blur:当前字段失去焦点时触发。
change:对于<input>和<textarea>元素,在失去焦点且value值改变时触发;对于<select>元素,在其选项改变时触发。
foucus:当前字段获得焦点时触发。
二、文本框脚本
在HTML中,有两种方式来表现文本框:一种是使用<input>元素的单行文本框,另一种是使用<textarea>的多行文本框。这两个控件非常相似,而且多数时候的行为也差不多。要表现文本框,必须将<input>元素的type特性设置为“text”。而通过设置size特性,可以指定文本框中能够显示的字符数。通过value特性,可以设置文本框的初始值,而maxlength特性则用于指定文本框可以接受的最大字符数。如果要创建一个文本框,让它能够显示25个字符,但输入不能超过50个字符,可以使用以下代码:
<input type=”text” size=”25” maxlength=”50” value=”initial value”>
相对而言,<textarea>元素则始终会呈现为一个多行文本框。要指定文本框的大小,可以使用rows和cols特性。其中,rows特性指定的是文本框的字符行数,而cols特性指定的是文本框的字符列数。与<input>元素不同,<textarea>的初始值必须要放在<textarea>和</textarea>之间。
另一个与<input>的区别在于,不能在HTML中给<textarea>指定最大字符数。
无论这两种文本框在标记中有什么区别,但它们都会将用户输入的内容保存在value属性中,可以通过这两个属性读取和设置文本框的值,如下面的例子:
var textarea = document.forms[0].elements[“textbox1”];
alert(textbox.value);
textbox.value = “Some new value”;
1.选择文本
上述两种文本框都支持select()方法,这个方法用于选择文本框中的所有文本。在调用select()方法时,大多数浏览器都会将焦点设置到文本框中。这个方法不接受参数,可以在任意时刻被调用。
(1)选择(select)事件
与select()方法对应的,是一个select事件。在选择了文本框中的文本时,就会触发select事件。在调用select()方法时也会触发select事件。
(2)取得选择的文本
虽然通过select事件我们可以知道用户什么时候选择了文本,但仍然不知道用户选择了什么文本。HTML5通过一些扩展方案解决了这个问题,以便更顺利地取得了选择的文本。该规范采取的办法是添加两个属性:selectionStar和selectionEnd。这两个属性中保存的是基于0的数值,表示所选择文本的范围。因此,要取得用户在文本框中选择的文本,可以使用如下代码:
function getSelectedText(textbox){
return textbox.value.substring(textbox.selectionStar , textbox.selectionEnd);
}
因为substring()方法基于字符串的偏移量执行操作,所以将selectionStar和selectionEnd直接传给它就可以取得选中的文本。
(3)选择部分文本
所有文本框都有一个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()之前或之后立即将焦点设置到文本框。
IE要选择文本框中的部分文本,必须先使用createTextRange()方法创建一个范围,然后使用moveStart()和moveEnd()这两个范围的方法将范围移动到位。不过,在调用这两个方法以前,还必须使用collapse()将范围折叠到文本框的开始位置。此时,moveStart()将范围的起点和终点移动到了相同的位置只要再给moveEnd()传入要选择的字符总数即可。最后一步,就是使用范围的select()方法选择文本。如下面的的例子所示:
textbox.value = “Hello world!” ;
var range = textbox.createTextRange();
//选择所有文本
range.collapse(true) ;
range.moveStart(“character” , 0) ;
range.moveEnd(“character” , textbox.value.length) ; //“Hello world!”
range.select( ) ;
2.过滤输入
(1)屏蔽字符
有时候,我们需要用户输入的文本中不包含某些字符。例如,电话号码中不能包含非数字字符,响应向文本框中插入字符操作的是keypress事件。可以通过阻止这个事件的默认值来屏蔽此类字符:
EventUtil.addHandler(textbox,“keypress”,function(event)){
event = EventUtil.getEvent(event);
EventUtil.preventDefault(event);
});
运行以上代码之后所有按键操作都会被屏蔽,结果导致文本框变成只读的。
2.操作剪贴板
HTML5中有以下6个剪贴板事件:
beforecopy:在发生复制操作前触发。
copy:在发生复制操作时触发。
beforecut:在发生剪切操作前触发。
cut:在发生剪切操作时触发。
beforepaste:在发生黏贴操作前触发。
paste:在发生黏贴操作时触发。
要访问剪贴板中的数据时,可以使用clipboardData对象。在IE中这个对象时window对象的属性,而其他浏览器中这个对象是相应的event对象的属性。clipboardData对象有三个方法:getData()、setData()和clearData()。其中,getData()用于从剪贴板中取得数据,它接受一个参数,即要取得的数据的格式。类似的,setData()方法的第一个参数也是数据类型,第二个参数是要放在剪贴板中的文件。
3.自动切换焦点
使用javascript可以从多个方面增强表单字段的易用性。其中,最常见的一种方式就是在用户填写完成当前字段时,自动将焦点切换到下一个字段。
4.HTML5约束验证API
(1)必填字段:
第一种情况是在表单字段中指定了required属性。如下面的例子:
<input type = “text” name = “username” required>
任何标注有required的字段,在提交表达时都不能空着。
(2)其他输入类型
HTML5为<input>元素的type属性又增加了几个值。其中,“email”和“url”是两个得到支持最多的类型。顾名思义,“email”类型要求输入的文本必须符合电子邮件地址的模式。
(3)数值范围
对所有这些数值类型的输入元素,可以指定min属性、max属性和step属性。例如,想让用户只能输入0到100的值,而且这个值必须是5的倍数,可以这样写代码:
<input type = “number” min = “0” max = “100” step = “5” name = “count”>
(4)输入模式
HTML5为文本字段新增了pattern属性。这个属性的值是一个正则表达式。
(5)检测有效性
使用checkValidity()方法可以检测表单中的某个字段是否有效。所有表单字段都有个方法,如果字段的值有效,这个方法返回true,否则返回false。
(6)禁用验证
通过设置novalidate属性,可以告诉表单不进行验证。
<form method = “post” action = “signup.php” novalidate>
<!—这里插入表单元素-->
</form>
三、选择框脚本
选择框是通过<select>和<option>元素创建的。
1.选择选项
对于只允许选择一项的选择框,访问选中项的最简单方式,就是使用选择框的selectedIndex属性。
var selectedOption = selectbox.options[selectbox.selectedIndex];
另一种选择项的方式,就是取得对某一项的引用,然后将其selected属性设置为true。例如,下面代码会选中选择框中的第一项:
selectbox.options[0].selected = true;
2.添加选项
可以使用javascript动态创建选项,并将它们添加到选择框中。添加选项的方式有很多,第一种就是使用如下所示的DOM方法:
var newOption = document.createElement(“option”);
newOption.appendChild(document.createTextNode(“Option text”)) ;
newOption.setAttribute(“value” , “Option value” ) ;
selectbox.appendChild(newOption) ;
以上代码创建了一个新的<option>元素,然后为它添加了一个节点,并设置value属性,最后将它添加到了选择框中。
第二种方式是使用Option构造函数来创建新选项。Option构造函数接受两个参数:文本和值;第二个参数可选。来看下面的例子:
var newOption = new Option(“Option text” , “Option value”) ;
selectbox.appendChild(newOption) ;
第三种方式是使用选择框的add()方法。DOM规定这两个方法接收两个参数:要添加的新选项和将位于新选项之后的选项。如果想在列表的最后添加一个选项,应该将第二个参数设置为null。
(3)移除选项
移除选项的方法有很多种:
首先可以使用DOM的removeChild()方法,为其传入要移除的选项,如下面的例子所示:
selecbox.removeChild(selectbox.option[0]); //移除第一个选项
其次,可以使用选择框的remove()方法。这个方法接收一个参数,即要移除的选项的索引,如下面的例子所示:
selectbox.remove[0]; //移除第一个选项
要清除选择框中所有的项,需要迭代所有选项并逐个移除它们,如下面的例子所示:
function clearSelectbox(selectbox){
for(var I = 0 , len = selectbox.options.length ; i < len ; i++){
selectbox.remove(i);
}
}
4.移动和重排选项
使用DOM的appendChild()方法,就可以将第一个选择框中的选项直接移动到第二个选择框中。下面的代码展示了将第一个选择框中的第一个选项移动到第二个选择框中的过程:
var selectbox1 = document.getElementById(“selLocations1”) ;
var selectbox2 = document.getElementById(“selLocations2”) ;
selectbox2.appendChild(selectbox1.options[0]) ;
要将选择框中的某一项移动到特定位置,最适合的DOM方法就是inserBefore();appendChild()方法只适用于将选项添加到选择框的最后。
四、表单序列化
以下是表单序列化的按钮:
function serialize(from){
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 “field”:
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(“&”);
}
如果表单中包含<fieldset>元素,则该元素会出现在元素集合中,但没有type属性。因此如果type属性未定义,则不需要对其进行序列化。
五、富文本编辑
富文本编辑又称为WYSIWYG。在网页中编辑富文本内容,这一技术的本质就是在页面中嵌入一个包含空HTML页面的iframe。通过设置designMode属性,这个空白的HTML页面可以被编辑,而编辑对象则是该页面<body>元素的HTML代码。designMode属性有两个可能的值:”off” 和 “on”。在设置为”on”时,整个文档都会变得可以编辑,然后就可以像使用字处理软件一样,通过键盘将文本加粗、变成斜体,等等。
可以给iframe指定一个非常简单的HTML页面作为其内容来源,例如:
<!DOCTYPE html>
<html>
<head>
<title>Blank Page for Rich Text Editing</title>
</head>
<body>
</body>
</html>
1.使用contenteditable属性
另一种编辑富文本内容的方式是使用名为contenteditable的特殊属性。可以把contenteditable属性应用给页面中的任何元素,然后用户就可以立即编辑该元素。
contenteditable属性有三个可能的值:”true”表示打开,”false”表示关闭,”inherit”表示从父元素那里继承。
2.操作富文本
与富文本编辑器交互的主要方式,就是使用document.execCommand()。这个方法可以对文档执行预定义的命令,而且可以应用大多数格式。可以为document.execCommand()方法传递3个参数:要执行的命令名称、表示浏览器是否应该为当前命令提供用户界面的一个布尔值和执行命令必须的一个值。
3.富文本选区
在富文本编辑器中,使用框架(iframe)的getSelection()方法,可以确定实际选择的文本。这个方法是window对象和document对象的属性,调用它会返回一个表示当前选择文本的Selection对象。
4.表单与富文本
由于富文本编辑器是使用iframe而非表单控件实现的,因此从技术上说,富文本编辑器并不属于表单。为此,通常可以添加一个隐藏的表单字段,让它的值等于从iframe中提取出的HTML。下面就是通过表单的onsubmit事件处理程序实现上述操作的代码:
EventUtil.addHandler(form , “submit” , function(event) {
event = EventUtil.getEvent(event) ;
var target = EventUtil.getTarget(event) ;
target.elements[“comments”].value = frames[“richedit”].document.body.innerHTML ;
} ) ;