表单(Form)是所有基于web的应用程序的关键组件。然而尽管它们如此重要,Web开发人员还是经常向用户提供一些难于使用的表单。下面是三个常见的问题:
- 表单太长。一个看起来无休无止的问题清单肯定会使用户点击后退(back)按键,或者跳到另外的网站。
- 在很多情况下,一个特定的用户只需要填写部分表单内容。如果您显示那些没有必要的问题,则实际上是加入导致页面混乱的信息,鼓励用户访问别的网页。
- 表单的输入通常需要按照特定的格式进行。然而把这种信息加入到Web页面上可能会使屏幕看起来混乱,而且没有吸引力。
这里有一个表单实例,即使是最无畏的用户也肯定会被赶走。本文将向您演示如何用少量的JavaScript来解决所有的这些问题,以及如何让您的网站用户得到更好的体验。
选择您希望的表单
我们可以用很多方法来缩短一个长的表单。举例来说,Internal Revenue Service(内部收入服务)就提供了很多简单的和复杂的表单版本;1040-A收入税表单也有一个较为简单的版本,即1040-EZ,提供给那些税务事务比较简单的人使用。
如果一个表单有多个版本,则我们的主要任务就变成如何把用户指向正确的表单。通常情况下,用一组简单的连接就可以了,比如:简单表点电击这里,复杂表单点击这里。还有一种可选的方法:用一个页面来显示多个可选表单,访问者可以通过收音机按钮在可选表单之间进行切换。这种方法对于复杂页面,或者慢速连接用户都特别好,因为装载新页面的时候没有延迟。请看一下这个用类似帧的方法作成的例子,它提供了多个表单。
这个方法使用了动态HTML(Dynamic HTML,即DHTML)技术,跟使用IFRAMES实现同样的任务相比,这个方法有几个好处。首先,DHTML提供了比IFRAMEs支持的更灵活的格式化手段。您可以把图像,边界,字体,和所有您知道的,可以用于HTML和层叠式风格表单(Cascading Style Sheets,即CSS)的技术应用到DHTML对象中,相比之下,IFRAMES几乎没有可以配置的功能。第二,如果有人在填写一个表单时,切换到另一个表单,然后再切换回来,那浏览器有很大的可能性会丢失开始时输入的信息。在基于DHTML的解决方案中,没有这个问题。第三,使用DHTML,您可以做一些比较有技巧的事,象裁剪,以及在页面上移动表单。您可以把IFRAMES和DHTML结合起来实现这些功能,但是首选还是只使用DHTML。
在choose_form.html页面中的实现方法相当直接,特别是当您读过Internet Developer(英特网开发者)上的隐藏/显示层这篇文章之后,就更有这种感觉。每一个表单被放在一个DIV中,而每一个DIV和一个收音机按钮相关联。在收音机按钮被选择时改变其相关联的DIV的可视性。您可以看一下这个例子的源代码。下面是对这个例子的简要分析。
首先,每一个表单处于它自己的DIV中。下面是包含表单的DIV在某种程度上的简化版本: <div id="ez"
style="position:absolute;top:100px;left:5px;visibility:hidden;">
<form name="ez_form" method="POST"
action="http://mydomain.com/cgi-bin/thanks.cgi">
<table>
<tr><td>Name:</td><td><input type="text"></td><tr>
<tr><td>Income:</td><td><input type="text"></td></tr>
</table>
<input type="submit">
</form>
</div>
这里有一些要点值得一提。首先,DIV有一个id(id="ez"),用于标识您要隐藏或者显示的DIV;其次,DIV有自己的风格信息,这个信息定位了DIV(position:absolute;top:100px;left:5px)并在页面首次装载时将它隐藏(visibility:hidden)。
技巧在于用收音机按钮来显示正确的DIV。下面是一个收音机按钮的代码: <input type="radio" name="form_type" value="ez"
onClick="switchDiv(ez);">Easy Form
点击这个按钮会调用 switchDiv() 函数,这个函数首先查看浏览器是否可以处理DHTML。如果可以的话,就首先调hideAll()函数,用以隐藏所有包含表单的DIV,然后再调用changeObjectVisibility()函数来显示被请求的DIV。
下面是 switchDiv() 函数: function switchDiv(div_id)
{
var style_sheet = getStyleObject(div_id);
if (style_sheet)
{
hideAll();
changeObjectVisibility(div_id, "visible");
}
else
{
alert("sorry, this only works in browsers that do Dynamic HTML");
}
}
首先,switchDiv()尝试用div_id这个id来获取DIV的风格信息。它使用的函数叫getStyleObject(),这个函数在隐藏和显示层这篇文章中有描述。getStyleObject()函数接收一个DIV的id,返回该DIV的风格信息,它负责处理与访问风格表单相关的跨浏览器问题,因此这个的脚本可以工作在Netscape 4.0+和Internet Explorer 4.0+浏览器上。如果页面的访问者使用更早期的浏览器,则getStyleObject()函数会返回假(false)。下面是这个函数的源代码,供您精读: function getStyleObject(objectId) {
// checkW3C DOM, then MSIE 4, then NN 4.
//
if(document.getElementById && document.getElementById(objectId)) {
return document.getElementById(objectId).style;
}
else if (document.all && document.all(objectId)) {
return document.all(objectId).style;
}
else if (document.layers && document.layers[objectId]) {
return document.layers[objectId];
} else {
return false;
}
}
回到switchDiv()函数:如果getStyleObject()函数成功返回一个风格表单,则hideAll()和changeObjectVisibility()函数就会被调用。
changeObjectVisibility()函数在隐藏和显示层这篇文章中也有描述。它接收两个参数,一个是即将被改变属性的DIV的id,另一个是该DIV的可视性属性值(可视或者隐藏): function changeObjectVisibility(objectId, newVisibility) {
// first get the objects stylesheet
var styleObject = getStyleObject(objectId);
// then if we find a stylesheet, set its visibility
// as requested
//
if (styleObject) {
styleObject.visibility = newVisibility;
return true;
} else {
return false;
}
}
首先,这个函数用getStyleObject()函数来访问DIV风格表单对象。如果该风格表单存在,则根据第二个参数的内容改变DIV的可视性。如果第二个参数的值是hidden(隐藏),DIV就变成隐藏状态;如果这个值为visible(可视),则DIV就变成可视状态。
脚本中的最后一个函数是hideAll(): function hideAll()
{
changeObjectVisibility("ez","hidden");
changeObjectVisibility("full","hidden");
changeObjectVisibility("superduper","hidden");
}
这个函数简单地三次调用changeObjectVisibility(),每次隐藏一个含有表单的DIV。
综合起来说,点击一个收音机按钮会调用switchDiv()函数,它又调用hideAll()来隐藏所有的DIV,然后再调用changeObjectVisibility()函数来显示恰当的DIV;点击另一个收音机按钮就会再次隐藏所有的DIV,以及显示您希望的DIV。
getStyleObject()函数和changeObjectVisibility()函数将会在本文的多个例子中用到。由于它们频繁地被使用,把它们转移到一个文件中是一个好的想法,这样可以被包含到以后的脚本中,如下所示: <script src="utility.txt"></script>
把用于很多脚本的函数放到一个独立的文档中通常都是一个好主意。这样,如果您希望改变其中一个函数,则只需要改变一个文档,而不必深入到每一个使用这个函数的脚本,并在脚本中进行修改了。
表单向导
您刚才已经看到,显示短一些的表单可以使那些不需要回答所有问题的人们日子好过一些。但是,对于那些的确需要回答很长的问题列表中的每一个问题的人们,又该如何呢?同样地,您也可以让他们愉快一些。
使长的问题列表变得更加“美味”的一个方法是把一个表单变成几个页面,就象软件应用程序中常见的向导程序那样。这种方法对访问者在特定时刻能够看见的问题数目加以限制,减少了用户因为恐惧而跑掉的可能性。同时,有人一旦经过了一个页面,或者回答了两个问题,就很可能填完所有信息。
很多网站把长的表单分成若干小的部分,而把每个部分都提交给运行在web服务器上的一个CGI脚本。绝大部分的电子商务网站把订购的表单至少分成三个表单:一个确认购买,一个收集送货信息,还有一个用来填写付帐信息。在第一个表单被提交之后,表单中的信息就被发送到web服务器上,服务器上的程序就把这些信息存储起来,并显示第二个表单。
这种方法就一个好处,就是逐步存储信息。举例来说,如果您正在做一个调查,则这种方法意味着即使访问者进行到一半就停止表单的填写,您仍然可以得到一些信息。这种方法的缺点是表单的每个部分都要独立地在客户和服务器之间来回传递。如果连接是慢速的,则意味着可能会因为响应缓慢而丢失访问者。这种方法也假定您对web服务器上的脚本引擎有访问权限,并且您知道如何书写服务器端的脚本。
另外一个比较不经常用的方法是用DHTML来显示表单的不同部分。把每个子表单放入她自己的DIV中,在开始的时候显示第一个DIV上的子表单,然后当访问者填完了这一部分内容后,用JavaScript把第一个DIV隐藏起来,然后显示第二个DIV。这种方法把表单分割成若干小块,节省了和服务器来回传递的时间,并且不要求访问服务器端的脚本。您可以在DHTML向导中查看这个例子是如何工作的,然后再看一下这个向导程序的源代码,看看代码中涉及到什么技术。
向导程序的工作机制
在向导程序的代码中有一些有趣的地方。首先,让我们看一下第二个DIV的稍微缩短过的版本: <div id="part2" style="position:absolute;top:150px;left:50px;visibility:hidden;">
<form name="pet_info">
<table>
<tr><td>Your pets name:</td>
<td><input name="petname" type="text"></td></tr>
</table>
<input type="button" value="prev"
onClick="switchDiv(part2, part1);">
<input type="button" value="next"
onClick="switchIfDone(this.form, part2, part3);">
</form>
</div>
这里也有一些要点值得一提。和以前一样,DIV有一个id,它使得JavaScript可以根据需要隐藏和显示DIV。这个DIV也有风格信息,用来定位DIV,并在页面首次装载时将之隐藏。
在DIV中存在一个含有一系列问题输入域的表单。请注意,表单有一个名字,每个问题输入域也都有一个名字。脚本程序在后面会根据这些名字从表单的不同部分收集数据。
除了这些问题域之外,在表单的尾部有两个按键。第一个按键使访问者可以回到原来的页面去改变问题的答案。它调用了switchDiv()函数并传入两个参数:即包含访问者正在查阅的表单部分的DIV id,以及包含即将被访问的表单部分的DIV id。第二个按键则使访问者一旦填完当前的表单部分之后可以移动到表单的下一个部分。它调用了switchIfDone()函数,这个函数接收三个参数:表单的属性名称,当前可见的DIV id,以及接下来即将被显示的DIV id。
大部分的工作由switchDiv()和switchIfDone()函数来完成。第一个函数相当直接: function switchDiv(this_div, next_div)
{
if (getStyleObject(this_div) && getStyleObject(next_div)) {
changeObjectVisibility(this_div, "hidden");
changeObjectVisibility(next_div, "visible");
}
}
这个函数和先前例子中看到的changeDiv()函数相类似。它用getStyleObject()函数来确认浏览器是否可以处理DHTML。如果可以的话,就调用changeObjectVisibility()函数将当前可见的DIV隐藏,并显示下一个应该被看见的DIV。
switchIfDone()函数负责确定表单是否完全被填充。如果表单已经完成,而用户正在查看表单的最后部分,则应该把所有表单上的所有信息发送到服务器上。如果用户正在查看的并不是向导程序的最后部分,则switchDiv()函数应该把页面移动到下一个表单。
当访问者点击表单上的next按键时,switchIfDone() 函数就会被调用,如下所示: <input type="button" value="next"
onClick="switchIfDone(this.form, part2, part3);">
第一个参数是一个指针,指向含有按键的表单。该函数将会检查表单是否填写正确,如果正确,就把第二部分隐藏,然后显示第三部分。
下面是判断表单是否填写完成的代码: var complete = true;
for (var loop=0; loop < the_form.elements.length; loop++)
{
if (the_form.elements[loop].value == "")
{
complete = false;
}
}
这个循环遍历了表单中的所有元素,确认这些元素是否都不为空。如果有一个元素为空,则把complete变量设置为假(false)。
一旦上述循环执行完成,函数接下来就运行如下代码: if ((complete == true) && (next_div == "finished"))
{
submitTheInfo();
}
|