8.2 显示错误信息
如果说表单验证程序的实现并不是很容易的话,那么显示错误的上下文信息,以帮助用户更好地填写表单,更是一个不小的挑战。你将用到前面所学习的技术,来构建一个完整的验证和信息显示系统。而在这一部分中你会看到表单的验证如何与信息显示的综合使用,并在适当的时候触发,让用户更容易理解。
8.2.1 验证
使用新的数据结构就可以构建一对牢固的、可扩展的函数,它们可用来校验整个表单或者单个字段并依此显示上下文错误信息。
实现表单动态验证的技术有好几种。第一种是浏览器所提供,并且是HTML DOM规范的组成部分。所有的<form>元素(在DOM中)都有一个被称为elements的属性,这个属性是一个包含表单所有字段的数组,使用这个数组就可以轻松地遍历所有可能的字段,并检查错误。
第二种技术也比较重要,它为所有字段附加class以触发不同的验证规则。比如,有class为required(必填)的字段要求必须填写。所有这些class都应该匹配由代码清单8-8所提供的规则集合。
使用这两种技术就可以构建这两个通用的函数了,它们能够验证整个表单和单个字段(两者在完整的功能性验证场合中都需用到)。这两个函数如代码清单8-9所示。
代码清单8-9 执行表单验证和触发错误信息显示的函数
// 验证表单所有字段的函数
// form参数应是一个表单元素的引用
// load参数应该是一个布尔值,用以判别验证函数在页面加载时执行还是动态执行
function validateForm( form, load ) {
var valid = true;
// 遍历表单的所有字段元素
// form.elements是表单所有字段的一个数组
for ( var i = 0; i < form.elements.length; i++ ) {
// 先隐藏任何错误信息,以防不意的显示
hideErrors( form.elements[i] );
// 检查字段是否包含正确的内容
if ( ! validateField( form.elements[i], load ) )
valid = false;
}
// 如果字段是不正确的内容返回false, 反之返回true
return valid;
}
// 验证单个字段的内容
function validateField( elem, load ) {
var errors = [];
// 遍历所有可能的验证技术
for ( var name in errMsg ) {
// 查看字段是否有错误类型指定的class
var re = new RegExp("(^|\\s)" + name + "(\\s|$)");
// 检查元素是否带有该class并把它传递给验证函数
if ( re.test( elem.className ) && !errMsg[name].test( elem, load ) )
// 如果没有通过验证,把错误信息增加到列表中
errors.push( errMsg[name].msg );
}
// 如果存在错误信息,则显示出来
if ( errors.length )
showErrors( elem, errors );
// 如果字段始终没有得到验证,返回false
return errors.length > 0;
}
或许你已经注意到这段代码尚缺乏两个函数,它们跟隐藏和显示验证的错误信息息息相关。基于你要显示错误信息的具体需求,你可能需要对这两个函数稍作调整。在这个特定的表单上,我决定在表单的每一个字段后显示错误信息。这两个函数如代码清单8-10所示。
代码清单8-10 显示和隐藏相应字段的错误信息
// 隐藏当前正显示的任何错误信息
function hideErrors( elem ) {
// 获取当前字段的下一个元素
var next = elem.nextSibling;
// 如果下一个元素是ul并有class为errors
if ( next && next.nodeName == "UL" && next.className == "errors" )
// 删掉它(这是我们“隐藏”的含义)
elem.parenttNode.removeChild( next );
}
// 显示表单内特定字段的错误信息
function showErrors( elem, errors ) {
// 获取当前字段的下一个元素
var next = elem.nextSibling;
// 如果该字段不是我们指定的包含错误的容器
if ( next && ( next.nodeName != "UL" || next.className != "errors" ) ) {
// 我们得生成一个
next = document.createElement(
"ul" );
next.className = "errors";
// 并在DOM中把它插入到恰当的地方
elem.paretNode.insertBefore( next, elem.nextSibling );
}
// 现在有了一个包含错误的容器引用,我们可以遍历所有的错误信息了
for ( var i = 0; i < errors.length; i++ ) {
// 为每一条错误信息创建新的li包裹器
var li = document.createElement( "li" );
li.innerHTML = errors[i];
// 并插入到DOM中
next.appendChild( li );
}
}
既然已经有了所有的JavaScript代码,剩下的步骤就是增加一些样式使其美观了。CSS代码如代码清单8-11所示。
代码清单8-11 使错误信息可读性更佳的CSS
ul.errors {
list-style: none;
background: #FFCECE;
padding: 3px;
margin: 3px 0 3px 70px;
font-size: 0.9em;
width: 165px;
}
最后,各方面终于凑齐了,你可以看到如图8-2所示的最终效果,它是JavaScript和样式化的综合结果(如果你对事件的监听感到为难的话,稍后会有解释)。
现在你已经详细地了解如何验证表单(以及它里面的字段)并显示基于任意字段验证的错误信息,但还需要决定在哪个合适的时候运行验证程序。所有的字段同时检验并不总是最好的,通常增量式检验才是最恰当的。接下来,我们会解释在各个合适的不同运行时间执行验证的优点。
8.2.2 何时验证
表单验证比较麻烦的一点是决定何时才是显示错误信息的合适时机。表单(或字段)有3个不同的验证时间点:表单提交时、字段改变时和页面加载时。它们都有各自的优缺点,稍后会分别讨论。使用上一部分提到的函数,这些过程都变得更简单和更容易理解。
1.表单提交时验证
在表单提交时验证是最常用的技术,因为它跟普通的表单验证技术最为接近。为监听表单的提交,你必须绑定一个事件处理函数,来等待用户完成表单并点击提交按钮(或敲击回车键)。但是用户是否在所有的字段都输入了内容并不是先决条件,一旦表单提交它就由规则集合所指定的各种规则去检验。如果任何一个字段不通过,表单会停止提交(这通过阻止提交事件处理函数的默认行为做到),而用户也会收到错误信息的提示,也有机会去更正错误。实现这个技术的代码如代码清单8-12所示。
代码清单8-12 在表单提交的时候运行表单验证函数
function watchForm( form ) {
// 监听表单的提交事件
addEvent( form, 'submit', function(){
// 确保表单内容通过验证
return validateForm( form );
});
}
// 获取页面的第一个表单
var form = document.getElementsByTagName( "form" )[0];
// 并在它提交的时候作出验证
watchForm( form );
2.在字段改变时验证
可用在表单验证的另一种技术是监听表单内单个字段的变化。虽然可以通过keypress事件达到,但往往会导致意想不到的结果。在一个字段里,每次敲击键盘都触发错误检查的话会让用户感到困惑和厌烦。在这种情况下,他们一开始输入电子邮件地址就看到错误信息提示地址不正确。但不应该是这样的,因为他们需要继续在这个字段输入内容。一般而言,这种方法并不值得推荐,它确实不是一种好的用户体验。
检查字段变化的第二种方法是直到用户离开字段才验证(这样用户可能已经完成了信息的填写)。这种情况下的验证提供的用户体验更为平滑,因为用户有充分的时间来完整填写所需信息,同时仍能较快地收到验证的错误信息。
实现这个技术的例子如代码清单8-13所示。
代码清单8-13 在运行任何字段验证函数之前监听字段的变化
function watchFields( form ) {
// 遍历表单内的所有字段
for ( var i = 0; i < form.elements.length; i++ ) {
// 并绑定'change'事件处理函数(它监听input元素的失焦)
addEvent( form.elements[i], 'change', function(){
// 一旦失去焦点,重验证该字段
return validateField( this );
});
}
}
// 定位到页面的第一个表单
var form = document.getElementsByTagName( "form" )[0];
// 监听表单所有字段的变化
watchFields( form );
3.在页面加载时验证
在页面加载时验证并不像前两者那么有必要,但在某些边缘场合也是非常重要的。假设用户在表单中输入信息后重新载入(或是由浏览器或应用程序本身预先填充了信息),在这些预加载的信息中有可能会触发错误。这个特定的技术在页面加载时运行表单验证程序,以验证已经存在的数据。这给予用户迅速处理错误的机会,而不用等到表单提交时才作出验证。
在页面加载时执行验证所需要的代码例子如代码清单8-14所示。
代码清单8-14 在页面加载时执行表单验证
addEvent( window, "load", function() {
// 获取页面的所有表单
var forms = document.getElementsByTagName("form");
// 遍历所有的表单
for ( var i = 0; i < forms.length; i++ ) {
// 逐一验证,记得设置参数'load'为ture, 它可以防止显示某些不必要的错误
validateForm( forms[i], true );
}
});
学习了所有不同的表单验证、显示错误信息的方式甚至是执行验证的恰当时机,你已经达到一个很高的目标——完成了客户端的表单验证。跨越这些障碍后,你可以进一步探索额外的一些技术了,使用这些技术可以提升整个表单和特定类型字段的可用性。






