表单脚本
文本框脚本
众所周知,在HTML中有两种文本框:一个是使用<input>
(type为text )的单行文本框,一个是使用<textarea>
的多行文本框。 <input type="text">
单行文本框:
size :指定文本框中能够显示的字符数(可能是按照最宽的那种字符,而字母细一点,能放多一点。)maxlength :指定文本框可以接受的最大字符数value :可填写初始值(长度可以超过maxlength),存放文本值。<textarea>
多行文本框:
rows :指定文本框的字符行数cols :指定文本框的字符列数(和size 类似)value :标签中没有该特性,只有存放文本值的功能(如要设置初始值,需要放在<textarea>初始值</textarea>
)。不能在HTML 中给<textarea>
指定最大字符数。 建议用value 属性读取或设置文本框的值,不建议使用标准的DOM 方法。即尽量不要用setAttribute 去设置input元素的value 特性,也不要修改textarea元素的第一个子节点。书中给的解释是,对value 属性所做的修改,不一定会反映在DOM中 。在看了后一篇文章后发现,比如select元素中某个option的value是空的,你对这个option取value会得到option的text值,而在此处你用getAttribute去获取option的value就会是null。
选择文本
两种文本框都有select() 方法,调用该方法后,大多数浏览器都会将焦点设置到文本框中,并选中所有文本。这么做可以方便用户删除或修改value值。例如要实现一个点击文本框后选中原先文本的功能:
window.addEventListener("load" , function (event) {
var textbox = document.forms[0 ].elements[0 ];
textbox.addEventListener("focus" , function (event) {
event.target.select();
});
textbox.focus();
});
利用focus事件,在文本框获得焦点后,调用select()方法选中所有文本。
select事件
与select()对应的是一个select事件。在选择了文本框的文本时,就会触发该事件。触发select 事件的时机会因浏览器而异。在IE9+、Opera、Firefox、Chrome和Safari 中,只有用户选择了文本(而且要释放鼠标),才会触发select 事件。而在IE8 及更早版本中,只要用户选择了一个字母(不必释放鼠标),就会触发select 事件。另外,在调用select()方法时也会触发select 事件。一个奇怪的现象:
<form method ="post" action ="javascript:alert('Form submitted!')" id ="myForm" >
<div >
<label for ="comments" > Any comments?</label > <br >
<textarea rows ="10" cols ="50" id ="comments" name ="comments" > Select some of this text.</textarea >
</div >
<input type ="button" value ="Select Text" id ="select-btn" >
<input type ="submit" value ="Submit Form" id ="submit-btn" >
</form >
<script type ="text/javascript" >
document.getElementById("comments" ).addEventListener("select" , function (event) {
console.log("Text is selected!" );
});
document.getElementById("select-btn" ).addEventListener("click" , function (event) {
console.log("1" );
document.getElementById("comments" ).select();
console.log("2" );
});
</script >
利用鼠标去选中文本在Chrome、Firefox、IE中都是正常如前所述的(IE8-需要调整代码)。但是点击select-btn却有不一样的效果。在Chrome中会是先打印1和2,再连续打印两个Text is selected! ,而在Firefox和IE中都是先1再Text is selected! 再2。可见这里Chrome 对select()的操作和Firefox有所不同。
取得选择的文本
通过select事件我们可以得知用户何时选择了文本,那么选择了哪些文本也是需要我们去考虑的。HTML5后通过扩展方法以便更顺利地取得选择的文本。它添加了两个属性:selectionStart和selectionEnd 。这两个属性中保存的是文本选区开头和结尾的偏移量。然后我们再通过substring方法即可获得选中的文本。 在IE8-中不支持这两个属性,但也可以通过其他手段获得选中的文本。IE8 及更早的版本中有一个document.selection 对象,其中保存着用户在整个文档范围内选择的文本信息;它无法确定用户是在页面哪个部位选择了文本,但我们可以让它和select事件一起使用。要取得选择的文本,首先得创建一个范围,然后再从中提取文本(第十二章)。
function getSelectedText (textbox) {
if (typeof textbox.selectionStart == "number" ){
return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd);
} else if (document.selection){
return document.selection.createRange().text;
}
}
选择部分文本
select()是选择所有文本,而通过setSelectionRange() (IE9+和其他大部分浏览器)则能选择部分文本。这个方法接收两个参数:要选择的第一个字符的索引和要选择的最后一个字符之后的字符的索引。
textbox.value = "Hello world!"
textbox.focus();
textbox.setSelectionRange(0 , 3 );
而IE8-之前的选择部分文本则需要利用范围 的知识(同样适用于IE9+)。
textbox.value = "Hello world!" ;
textbox.focus();
var range = textbox.createTextRange();
range .collapse(true );
range .moveStart("character" , 0 );
range .moveEnd("character" , textbox.value.length);
range .select ();
range .collapse(true );
range .moveStart("character" , 0 );
range .moveEnd("character" , 3 );
range .select ();
range .collapse(true );
range .moveStart("character" , 4 );
range .moveEnd("character" , 3 );
range .select ();
过滤输入
屏蔽字符
有时候,我们需要用户输入的文本中包含或不包含某些字符。例如只允许输入数字字符:
var input = document.forms[0 ].elements[0 ];
input.addEventListener("keypress" , function (e) {
var charCode= String .fromCharCode(e.charCode);
if (!/\d/ .test(charCode)) {
e.preventDefault();
}
});
有些浏览器(例如Firefox)也会对非输入字符触发keypress事件,例如向上向下退格。这意味着,仅考虑到屏蔽不是数值的字符还不够,还要避免屏蔽这些极为常用和必要的键。在Firefox 中,所有由非字符键触发的keypress 事件对应的字符编码为0,而在Safari 3 以前的版本中,对应的字符编码全部为8。所以我们改写一下上面的代码就可以解决这个问题:
var input = document.forms[0 ].elements[0 ];
input.addEventListener("keypress" , function (e) {
var charCode= String .fromCharCode(e.charCode);
if (!/\d/ .test(charCode) && e.charCode > 9 ) {
e.preventDefault();
}
});
除此之外,还有一个问题需要处理:复制、粘贴及其他操作还要用到Ctrl 键。例如在Firefox中前面的代码,也会屏蔽Ctrl+C、Ctrl+V,以及其他使用Ctrl 的组合键。因此,还要确保用户没有按下Ctrl 键。
if (!/\d/.test (charCode) && e.charCode > 9 && !e.ctrlKey ) {
e.preventDefault ()
}
操作剪切板
下列是6 个剪贴板事件:
beforecopy :在发生复制操作前触发。copy :在发生复制操作时触发。beforecut :在发生剪切操作前触发。cut :在发生剪切操作时触发。beforepaste :在发生粘贴操作前触发。paste :在发生粘贴操作时触发。 copy、cut 和paste 事件,只要是在上下文菜单 中选择了相应选项,或者使用了相应的键盘组合键 ,所有浏览器都会触发它们。而对应的3个before事件 ,触发事件因浏览器而异。有些浏览器会在显示针对文本框的上下文菜单时触发,而有些浏览器则会在发生前面三个事件前触发(例如执行copy操作,会依次触发beforecopy和copy事件 )。阻止或取消3个before事件不会取消对剪切板的操作,只有取消了copy、cut 和paste 事件,才能阻止相应操作发生。
<script>
var input = document.forms [0 ].elements [0 ]
function consolelog(e) {
console.log (e.type )
}
function preventDefault(e) {
console.log (e.type )
e.preventDefault ()
}
input.addEventListener ("beforecopy" , preventDefault)
input.addEventListener ("copy" , consolelog)
input.addEventListener ("beforecut" , preventDefault)
input.addEventListener ("cut" , consolelog)
input.addEventListener ("beforepaste" , preventDefault)
input.addEventListener ("paste" , consolelog)
</script>
--------------------------IE版本可以和上面合并,但是我懒
<script>
var input = document.forms [0 ].elements [0 ]
function consolelog(e) {
console.log (e.type )
}
function preventDefault(e) {
console.log (e.type )
event.returnValue = false
}
input.attachEvent ("onbeforecopy" , preventDefault)
input.attachEvent ("oncopy" , consolelog)
input.attachEvent ("onbeforecut" , preventDefault)
input.attachEvent ("oncut" , consolelog)
input.attachEvent ("onbeforepaste" , preventDefault)
input.attachEvent ("onpaste" , consolelog)
</script>
针对上面这段代码,测试效果如下: 在Chrome 中,两个事件会在执行操作后依次触发,不会执行beforepaste 事件。before事件preventDefault无效。对对应的操作preventDefault有效。 在Firefox 中,不会执行3个before 事件。其余和Chrome 一样。 在IE中,6个事件都会执行。3个before 事件在选中文本并呼出上下文菜单的时候会依次触发 beforecut、beforecopy、beforepaste、beforecut、beforecopy、beforepaste 事件。如果没有选中文本右键则不会触发beforecut 事件。即依次触发 beforecopy、beforepaste、beforecopy、beforepaste 事件。 要取得剪切板中的数据,可用使用clipboardData 对象,在IE中,这个对象是window 对象的属性。在其余大多数浏览器中,这个对象是相应event 对象的属性。这个clipboardData 对象有三个方法:getData()、setData()和clearData() 。这个date 就是指我们复制或剪切的对象。其中,getData() 用于从剪贴板中取得数据,它接受一个参数,即要取得的数据的格式。在IE 中,有两种数据格式:“text”和”URL” 。在Firefox、Safari 和Chrome 中,这个参数是一种MIME 类型;不过,可以用”text”代表”text/plain”。setData() 需要传入两个参数(第一个为”text”或”text/plain”)。
var textbox = document.forms[0 ].elements[0 ];
if (textbox.addEventListener) {
textbox.addEventListener("paste" , function (event) {
var clipboardData = event.clipboardData || window.clipboardData;
var text = clipboardData.getData("text" );
if (!/^\d*$/ .test(text)){
event.preventDefault();
}
});
} else {
textbox.attachEvent("onpaste" , function (event) {
event = window.event;
var clipboardData = window.clipboardData;
var text = clipboardData.getData("text" );
if (!/^\d*$/ .test(text)){
event.returnValue = false ;
}
});
}
而setData() 并不会影响剪切板,在IE 中getData 会获得之前setData 的值,但是也不会被放入剪切板。clearData 其实就是setData 第二个参数传入null。但是也只有在事件处理程序中getData 才是null (IE),对剪切板没有影响。
自动切换焦点
在我们填写序列号的时候,一般注册码的格式形如:12345-67890-12345之类的,它通常会划分为3个输入框。填完第一个框一般会自动获取下一个输入框的焦点,方便继续填写。以下是实现代码:
<!DOCTYPE html>
<html lang ="en" >
<head >
<meta charset ="UTF-8" >
<title > Title</title >
</head >
<body >
<form >
请填写序列号:
<input type ="text" maxlength ="5" size ="5" >
-
<input type ="text" maxlength ="5" size ="5" >
-
<input type ="text" maxlength ="5" size ="5" >
-
<input type ="text" maxlength ="5" size ="5" >
-
<input type ="text" maxlength ="5" size ="5" >
</form >
</input >
<script >
var form = document.forms[0 ];
var input = form.querySelectorAll("input[type='text']" );
for (var i=0 ,len=input.length;i<len;i++) {
input[i].addEventListener("keyup" , (function (nextElement) {
return function (e) {
var target = e.target;
if (target.value.length == target.maxLength) {
nextElement.focus();
}
}
})(input[i==len-1 ?0 :i+1 ]));
input[i].addEventListener("focus" , function (e) {
e.target.select();
});
}
</script >
</body >
</html >
利用了选择符API(querySelectorAll)和keyup事件,中间的处理是为了避免闭包引发的错误,所以直接将下一个input的引用传进去而不是在闭包内用i,当然也可以将i传进去,但不如直接传来的清晰。最后根据maxLength和value.length判断是否跳到下一个input。
HTML5 约束验证API
为了在将表单提交到服务器之前验证数据,HTML5 新增了一些功能。浏览器自己会根据标记中的规则执行验证,然后自己显示适当的错误消息(完全不用JavaScript 插手)。这个功能只有在支持HTML5 这部分内容的浏览器中才有效,这些浏览器有Firefox 4+、Safari 5+、Chrome 和Opera 10+ 。
必填字段
第一种情况是在表单字段中指定了required 属性,如下面的例子所示:
<form action ="javascript:alert(1)" >
<input type ="text" name ="username" required >
<textarea required > </textarea >
<select required >
<option value ="" > </option >
<option value ="1" > 1</option >
<option value ="2" > 2</option >
</select >
<button > tij</button >
</form >
。这个属性适用于<input>、<textarea>和<select>
字段,在JavaScript 中,通过对应的required 属性,可以检查某个表单字段是否为必填字段。
其他输入类型
HTML5 为<input>
元素的type 属性又增加了几个值。这些新的类型不仅能反映数据类型的信息,而且还能提供一些默认的验证功能。其中,“email”和”url” 是两个得到支持最多的类型,各浏览器也都为它们增加了定制的验证机制。要注意的是,如果不给<input>
元素设置required 属性,那么空文本框也会验证通过。
<form action ="javascript:alert(1)" >
<input type ="email" name ="email" >
<input type ="url" name ="homepage" >
</select >
<button > tij</button >
</form >
数值范围
除了”email”和”url”,HTML5 还定义了另外几个输入元素。这几个元素都要求填写某种基于数字的值:“number”、”range”、”datetime”、”datetime-local”、”date”、”month”、”week”,还有”time”。 这些type可以阻止用户输入不符合数值的类型而不仅仅在验证阶段。浏览器对这几个类型的支持情况并不好,因此如果真想选用的话,要特别小心。 例如number类型,可以指定min 属性(最小的可能值)、max 属性(最大的可能值)和step 属性(从min 到max 的两个刻度间的差值)
<input type="number" min ="0" max ="100" step ="5" name="count" >
在部分浏览器(如Chrome、Firefox)中还能看到能够自动递增和递减的数值调节按钮。 此外通过JavaScript也可以操作
input.stepUp();
input.stepUp(5 );
input.stepDown();
input.stepDown(10 );
输入模式
HTML5 为文本字段新增了pattern 属性。这个属性的值是一个正则表达式,用于匹配文本框中的值。下面的例子验证input的输入是否为数值。
<input type ="text" pattern="\d+" name="count" >
注意,模式的开头和末尾不用加^和$符号(假定已经有了)。这个特性不能阻止用户输入不符合的文本,仅仅在验证阶段体现。 在JS中可以通过下面代码去访问模式:
var pattern = document.forms [0 ].elements [0 ].pattern
检测有效性
有效性可以这么理解,就是填写进表单中的文本是否符合我们所加的验证。像上面的pattern通常只有在提交表单的时候,会先自动检测有效性,再选择是否提交。而我们可以通过input.checkValidity() (返回类型为Boolean )方法直接对某个字段进行有效性检测。如果要检测整个表单是否有效,则只要对表单引用 调用这个方法就行了。它会自上而下对每个字段进行验证。 与checkValidity() 方法简单地告诉你字段是否有效相比,validity 属性则会告诉你为什么字段有效或无效。这个对象包含一系列属性,每个属性会返回一个布尔值。
customError :如果设置了setCustomValidity(),则为true,否则返回false。patternMismatch :如果值与指定的pattern 属性不匹配,返回true。rangeOverflow :如果值比max 值大,返回true。rangeUnderflow :如果值比min 值小,返回true。stepMisMatch :如果min 和max 之间的步长值不合理,返回true。tooLong :如果值的长度超过了maxlength 属性指定的长度,返回true。有的浏览器(如Firefox 4)会自动约束字符数量,因此这个值可能永远都返回false。typeMismatch :如果值不是”mail”或”url”要求的格式,返回true。valueMissing :如果标注为required 的字段中没有值,返回true。valid :如果这里的其他属性都是false,返回true。checkValidity()也要求相同的值。
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." )
}
}
禁用验证
通过设置表单的novalidate 属性,可以告诉表单不进行验证。
<form method ="post" action ="signup.php" novalidate >
</form >
在JavaScript 中使用noValidate 属性可以取得或设置这个值,如果这个属性存在,值为true,如果不存在,值为false。