
2.2 处理各种类型的表单元素
表单(Form)是在HTML1.0草案时代就被支持的古老概念,因为HTML没有1.0版,所以表单元素最早在HTML2.0中被规范,这么古老的对象至今依然被广泛使用,这就证明其意义所在。
2.2.1 input、textarea、hidden和button
随着网站的发展,需求会不断发生变化,比如要在【范例2-4】基础上增加“简介”字段,可以为空,但是最长不超过60个字符,同时要统计一下,用户输入错误的次数,输入超过3次,就锁定“注册”按钮,然后要“解锁”才能重新使用,根据业务需求基于【范例2-4】增加的代码如【范例2-5】所示。
【范例2-5 处理各种类型的表单一】
1. <! DOCTYPE html> 2. <html> 3. <head> 4. <title>处理各种类型的表单一</title> 5. </head> 6. <body> 7. <form method="post" action="" onsubmit="return eg.regCheck(); "> 8. <input type="hidden" name="" id="errnum" value="0"/> 9. 账户:<input type="text" name="" id="userid" /><br /><br /> 10. 密码:<input type="password" name="" id="userpwd" /><br /><br /> 11. 确认:<input type="password" name="" id="userpwd2" /><br /><br /> 12. 简介:<textarea name="" rows="4" cols="18" id="about"></textarea> <br /><br /> 13. <input type="submit" value=" 注 册 " id="regBtn" /> <input type= "button" value="解锁" onclick="eg.unlock()" style="display:none; " id="regUnlock" /> 14. </form> 15. <script> 16. var eg = {}; //声明一个对象,当作命名空间来使用,本书默认的范例都会以此来方便管理 17. //定义一个公共函数来获取指定id 元素,减少代码量,提高代码复用率 18. eg.$ = function(id){ 19. return document.getElementById(id); 20. }; 21. //主要的验证方法 22. eg.regCheck = function(){ 23. var uid = eg.$("userid"); 24. var upwd = eg.$("userpwd"); 25. var upwd2 = eg.$("userpwd2"); 26. if(uid.value == ''){//value 是元素自带属性 27. alert(’账户不能为空!'); 28. eg.err(); 29. return false; 30. } 31. if(upwd.value == ''){ 32. alert(’密码不能为空!'); 33. eg.err(); 34. return false; 35. } 36. if(upwd.value ! = upwd2.value){ 37. alert(’两次密码输入不相同!'); 38. eg.err(); 39. return false; 40. } 41. //新增的部分 42. var about = eg.$("about"); 43. if(about.value.length>60){ //value 是字符串类型的属性 44. alert(’简介太长!'); 45. eg.err(); 46. return false; 47. } 48. return true; //返回true 就会提交表单form 49. }; 50. //出错时记录错误次数 51. eg.err = function(){ 52. var el = eg.$("errnum"); 53. var old = el.value; 54. el.value = parseInt(old)+1; //把字符串转换为整数+1,并保存起来 55. eg.lock(); //用来检查是否应该锁定 56. }; 57. //通过次数判断是否要锁定注册 58. eg.lock = function(){ 59. var err = eg.$("errnum"); 60. if(parseInt(err.value)>2){ 61. eg.$("regBtn").disabled = true; //根据业务需求,输错3 次就锁定 62. eg.$("regUnlock").style.display="block"; //同时显示解锁按钮 63. } 64. }; 65. //解锁 66. eg.unlock = function(){ 67. eg.$("regBtn").disabled = false; //根据业务需求,解锁就是让用户可以重新注册 68. eg.$("regUnlock").style.display="none"; //元素所有样式都挂载到style 属性下 69. } 70. </script> 71. </body> 72. </html>
从【范例2-5】的代码可看出,以前直接提示错误信息就行了,现在还要做错误统计,这些统计数据非常有用,可以为后台系统保存起来用于分析用户的错误率,甚至可以分析出用户一般会在哪些字段上出错。记录错误信息的数据不需要给用户看到,可以选择input的type属性是hidden的元素来存储。用户第3次注册出错时的界面如图2-5所示。

图2-5 【范例2-5】用户第3次注册失败的效果图
2.2.2 checkbox、radio和select
永远别期待自己写的代码会运行很久,就算没有bug,需求也总是在变化的。
例如,有人告诉你【范例2-5】收集的信息太少了,需要知道用户“性别”,还需要知道用户“年龄”段,然后还要选择兴趣爱好,最好是让用户必须选择一个。这些需求都必须实现,最终的代码见【范例2-6】。
【范例2-6 处理各种类型的表单二】
1. <! DOCTYPE html> 2. <html> 3. <head> 4. <title>处理各种类型的表单二</title> 5. </head> 6. <body> 7. <form method="POST" onSubmit="return eg.regCheck(); "> 8. <input type="hidden" name="" id="errnum" value="0"/> 9. 账户:<input type="text" name="" id="userid" /><br /><br /> 10. 密码:<input type="password" name="" id="userpwd" /><br /><br /> 11. 确认:<input type="password" name="" id="userpwd2" /><br /><br /> 12. 性别:<input type="radio" name="sex" value="1" checked="checked"/> 男 <input type="radio" name="sex" value="0"/>女 <br /><br /> 13. 年龄:<select name="" id="age"> 14. <option value="0" selected="selected">请选择年龄段</option> 15. <option value="1">18 岁以下</option> 16. <option value="2">18-24 岁</option> 17. <option value="3">24-30 岁</option> 18. <option value="4">30-35 岁</option> 19. <option value="5">35 岁以上</option> 20. </select><br/><br/> 21. 爱好:<input type="checkbox" name="like" value="1" class="like"/> 上网 <input type="checkbox" name="like" value="2" class="like"/> 逛街<input type="checkbox" name="like" value="3" class="like"/> 看电影 <input type="checkbox" name="like" value="4"class="like"/> 其他 <br/><br/> 22. 简介:<textarea name="" rows="4" cols="18" id="about"></textarea> <br/><br/> 23. <input type="submit" value="注册" id="regBtn" /> <input type= "button" value="解锁" onclick="eg.unlock()" style="display:none; " id="regUnlock" /> 24. </form> 25. <script> 26. var eg = {}; //声明一个对象,当作命名空间来使用,本书默认的范例都会以此来方便管理 27. //定义一个公共函数来获取指定id 元素,减少代码量,提高代码复用率 28. eg.$ = function(id){ 29. return document.getElementById(id); 30. }; 31. //主要的验证方法 32. eg.regCheck = function(){ 33. var uid = eg.$("userid"); 34. var upwd = eg.$("userpwd"); 35. var upwd2 = eg.$("userpwd2"); 36. if(uid.value == ''){ 37. alert(’账户不能为空!'); 38. eg.err(); 39. return false; 40. } 41. if(upwd.value == ''){ 42. alert(’密码不能为空!'); 43. eg.err(); 44. return false; 45. } 46. if(upwd.value ! = upwd2.value){ 47. alert(’两次密码输入不相同!'); 48. eg.err(); 49. return false; 50. } 51. //新增的部分 52. var about = eg.$("about"); 53. if(about.value.length>60){ 54. alert(’简介太长!'); 55. eg.err(); 56. return false; 57. } 58. //第二次新增的部分 59. var age = eg.$("age"); //下拉选项框 60. if(age.value == "0"){ 61. alert(’请选择年龄段!'); 62. eg.err(); 63. return false; 64. } 65. 66. var likes = document.getElementsByClassName("like"); 67. var likeNum = 0; 68. for(var n=0; n<likes.length; n++){ 69. if(likes[n].checked){ 70. likeNum++; 71. } 72. } 73. if(likeNum==0){ 74. alert(’请至少选择一个爱好!'); 75. eg.err(); 76. return false; 77. } 78. return true; //返回true 就会提交表单form 79. }; 80. //出错时记录错误次数 81. eg.err = function(){ 82. var el = eg.$("errnum"); 83. var old = el.value; 84. el.value = parseInt(old)+1; //把字符串转换为整数+1,并保存起来 85. eg.lock(); //用来检查是否应该锁定 86. }; 87. //通过次数判断是否要锁定注册 88. eg.lock = function(){ 89. var err = eg.$("errnum"); 90. if(parseInt(err.value)>2){ 91. eg.$("regBtn").disabled = true; //根据业务需求,输错3 次就锁定 92. eg.$("regUnlock").style.display="block"; //同时显示解锁按钮 93. } 94. }; 95. //解锁 96. eg.unlock = function(){ 97. eg.$("regBtn").disabled = false; //根据业务需求,解锁就是让用户可以重新注册 98. eg.$("regUnlock").style.display="none"; 99. } 100. </script> 101. </body> 102. </html>
最让人痛苦的事情是好不容易写好代码,用Firefox调试一切正常,提交测试部门进行测试。这代码怎么不兼容IE 6、IE 7呢?
看看在IE 6下到底是怎么回事呢?图2-6不容易看到,在运行时它会一闪而过,也无任何提示,这也是未达到预期验证效果的原因。

图2-6 IE 6下报错信息
在IE 6下document不支持getElementsByClassName方法,怎么办呢?那就得写一套兼容的代码放到eg.regCheck方法前,见【范例2-7】。
【范例2-7 兼容各浏览器的获取指定class名称元素集合的方法】
1. //定义一个公共函数来获取指定class 名称的元素集合,能兼容各个浏览器 2. eg.getElementsByClassName = function(className, element) { 3. if(document.getElementsByClassName){ //如果浏览器支持,直接返回 4. return(element||document).getElementsByClassName(className); 5. } 6. var children = (element || document).getElementsByTagName('*'); //使用通配符 7. var elements = new Array(); 8. 9. for (var i = 0; i < children.length; i++) { 10. var child = children[i]; 11. var classNames = child.className.split(' '); //分割多个class 样式 12. for (var j = 0; j < classNames.length; j++) { 13. if (classNames[j] == className) { 14. elements.push(child); 15. break; 16. } 17. } 18. } 19. return elements; 20. };
【范例2-6】原66行也要改为:
var likes = eg.getElementsByClassName("like");
再次运行后,终于在IE 6中得到了预期的验证效果,如图2-7所示。

图2-7 预期的验证效果
兼容性是令人头疼的历史遗留问题,因此jQuery这类框架才会应运而生,jQuery相关信息可以参看第四篇中的内容,jQuery从2版本开始也放弃了对IE 6的兼容问题,因为目前已经很少有人再使用IE 6,所以本书后面也会更少提及这类兼容问题。