JS教程:线小测试程序
9.3 在线小测试程序
在本章中,我们将对“在线小测试”程序作两处修改。一是允许用户首先选择回答完问题所需要的时间,二是允许用户选择要回答多少个问题。
要把“在线小测试”程序转换为一个基于计时器的程序,只需修改两个页面,即QuizPage.htm页面和GlobalFunctions.htm页面。
首先,需要修改的是QuizPage.htm页面中小测试程序的开始表单,在新的程序中,将允许用户选择要回答多少个问题以及答题的时间限制。接下来,还要修改cmdStartQuiz_onclick()函数,使得当在cmdStartQuiz_onclick()函数中调用resetQuiz()函数时,能够传入两个参数,一个参数表示答题的时间限制,另一个参数表示用户选择回答问题的数量。其中,resetQuiz()函数是定义在GlobalFunctions.htm页面中的。
现在,我们讨论一下GlobalFunctions.htm页面本身,在GlobalFunctions.htm页面中,需要修改resetQuiz()函数,以便根据用户选择的时间限制启动一个计时器。另外,还需要创建两个新的函数,以便对计时进行显示和处理:一个函数将在浏览器窗口的状态栏中显示剩余的时间以便提示用户,另一个函数将处理当计时器到点时的情况。
首先,我们来修改QuizPage.htm页面,将QuizPage.htm页面在文本编辑器中打开。
在QuizPage.htm页面中,frmQuiz表单目前仅包含一个按钮,将该表单修改为如下所示的代码:
<form name="frmQuiz">
<p>
Number of Questions <br>
<select name="cboNoQuestions" size="1">
<option value="3">3
<option value="5">5
</select>
</p>
<p>
Time Limit <br>
<select name="cboTimeLimit" size="1">
<option value="-1">No Time Limit
<option value="60">1 Minute
<option value="180">3 Minutes
<option value="300">5 Minutes
</select>
</p>
<input name=cmdStartQuiz type=button value="Start Quiz"
onclick="return cmdStartQuiz_onclick()">
</form>
在该表单中,添加了两个新的<select>标记,以创建两个下拉列表框。第一个下拉列表框允许用户选择愿意回答多少个问题,第二个下拉列表框则允许用户设置回答问题的时限。
接下来,修改页面顶部的cmdStartQuiz_onclick()函数。
<script language=JavaScript>
function cmdStartQuiz_onclick()
{
var cboNoQuestions = document.frmQuiz.cboNoQuestions;
var noQuestions =
cboNoQuestions.options[cboNoQuestions.selectedIndex].value;
var cboTimeLimit = document.frmQuiz.cboTimeLimit;
var timeLimit = cboTimeLimit.options[cboTimeLimit.selectedIndex].value;
window.top.fraTopFrame.fraGlobalFunctions.resetQuiz(noQuestions,
timeLimit);
window.location.href = "AskQuestion.htm";
}
</script>
cmdStartQuiz_onclick()函数被连接到了cmdStartQuiz按钮的onclick事件处理器,以便用户启动在线小测试程序。在上一版本的在线小测试程序中,仅仅调用了位于全局模块中的resetQuiz()函数,并加载AskQuestion.htm页面。现在,我们需要获取用户在下拉列表框中选中的问题数量和时间限制。后面我们还将看到,resetQuiz()函数也做出了相应的修改,以便接收两个参数—— 用户选择的问题数量和时间限制。
在cmdStartQuiz_onclick()函数中,定义了变量cboNoQuestions以引用表单中的cboNoQuestions下拉列表框,cboNoQuestions控件就是供用户选择回答多少个问题的下拉列表框。使用变量cboNoQuestions可以避免对document对象和表单对象的冗长引用,使得代码保持简洁易读。
在cmdStartQuiz_onclick()函数的第二行代码中,获取了cboNoQuestions下拉列表框中所选中的值,即用户选择要回答多少个问题,并将该值保存在变量noQuestions中。
随后的两行代码完成了类似的功能,用变量cboTimeLimit来引用表单中的cboTimeLimit下拉列表框,然后获取了cboTimeLimit下拉列表框中所选中的值,即用户所选择的回答问题的时间限制,并将该值保存在变量timeLimit中。
在接下来的那行代码中,复位了小测试程序,并将两个参数noQuestions和timeLimit传递给window.top.fraTopFrame.fraGlobalFunctions.resetQuiz()方法。其中,参数noQuestions表示问题数量,参数timeLimit表示时间限制。
这样就完成了对QuizPage.htm页面的修改。将该页面进行保存后,即可关闭文本编辑器。
现在,我们将注意力转移到GlobalFunctions.htm页面,首先来看一下需要修改的resetQuiz()函数,相应代码如下所示:
function resetQuiz(numberOfQuestions, SelectedTimeLimit)
{
timeLeft = SelectedTimeLimit;
totalQuestionsToAsk = numberOfQuestions;
var indexCounter;
currentQNumber = -1;
questionsAsked = new Array();
for (indexCounter = 0; indexCounter < questions.length;indexCounter++)
{
questionsAsked[indexCounter] = false;
}
numberOfQuestionsAsked = 0;
numberOfQuestionsCorrect = 0;
if (timeLeft == -1)
{
window.status = "No Time Limit";
}
else
{
quizTimerId = window.setInterval("updateTimeLeft()",1000);
}
}
首先修改的是resetQuiz()函数的定义。在上一版本的在线小测试程序中,resetQuiz()函数并不接收参数。现在,resetQuiz()函数将接收两个参数,这两个参数分别表示问题数量和时间限制。
接着,将全局变量timeLeft的值设置为参数SelectedTimeLimit的值,将全局变量totalQuestionsToAsk的值设置为参数numberOfQuestions的值。在后面的代码中你将会看到,这两个全局变量将用以判断问题是否已经回答完毕,以及检查时间限制是否已经到点。
在resetQuiz()函数的最后,添加了一个计时器,以监测剩余的时间。一种情况是计时器已经到点,剩余时间已经用完,即变量timeLeft的值为–1。如果变量timeLeft的值为–1时,则使用window对象的status属性,在浏览器的状态栏中显示一条时间到点的信息。注意,在Netscape浏览器中,当框架页改变时,将在浏览器的状态栏中显示Document:Done以覆盖No Time Limit信息。如果变量timeLeft的值不是–1,则使用setInterval()方法启动一个计时器,以每隔1s调用一次updateTimeLeft()函数。
updateTimeLeft()函数是一个新添加的函数。下面的代码用以创建updateTimeLeft()函数。将该代码添加在脚本块其他函数的下面。
function updateTimeLeft()
{
timeLeft--;
if (timeLeft == 0)
{
alert("Time’s Up");
numberOfQuestionsAsked = totalQuestionsToAsk;
window.top.fraQuizPage.location.href = "AskQuestion.htm";
}
else
{
var minutes = Math.floor(timeLeft / 60);
var seconds = timeLeft - (60 * minutes);
if (minutes < 10)
minutes = "0" + minutes;
if (seconds < 10)
seconds = "0" + seconds;
window.status = "Time left is " + minutes + ":" + seconds;
}
}
updateTimeLeft()函数完成了3个功能。首先,它将剩余时间减1,即timeLeft--;然后判断是否还有剩余的时间,当剩余时间为0时,则停止小测试程序;否则,在浏览器的状态栏中显示剩余的时间,以便提示用户。
前面我们已经知道,当调用resetQuiz()函数时,将复位在线小测试程序,并将全局变量timeLeft设置为以秒为单位的时限值,在规定的时间内用户必须完成小测试。每隔1s将调用一次updateTimeLeft()函数,在updateTimeLeft()函数的第一行代码中,将剩余的时间减去1s:
timeLeft--;
其后的if语句用以检查timeLeft是否为0,即是否还有剩余时间。如果timeLeft为0,则表示无剩余时间,这时将变量numberOfQuestionsAsked的值设置为全局变量totalQuestionsToAsk的值,即用户所选择的要回答问题的数量。接着,将页面导航到AskQuestion.htm页面,在该页面中将认为问题已经回答完毕并终止小测试程序,而不是继续提出一个新问题。
如果还有剩余时间,则该if语句的else子句将被执行,并更新浏览器的状态栏,以显示剩余的分钟数和秒数。
这里,需要将timeLeft中保存的以秒为单位的时间值拆分成分钟数和秒数。首先,可以使用下面这行代码获取分钟数的值:
var minutes = Math.floor(timeLeft / 60);
上面的代码将返回变量timeLeft中保存的总秒数除以60的商的整数部分,这正是我们所需要的分钟数。而下面的代码则用以获得秒数:
var seconds = timeLeft - (60 * minutes);
在上面的代码中,用总的秒数timeLeft减去分钟数所对应的秒数,即可得到除去分钟数之后剩余的秒数。例如,如果timeLeft是61,则分钟数为:
minutes = 61 / 60 = 1.01667
取整后将返回整数1,表示1分钟,而剩余的秒数为:
seconds = 61 - (60 * 1) = 1
我们希望按“分钟:秒钟”的格式将剩余时间显示在浏览器的状态栏中,例如对于上面的例子,希望将剩余时间显示为01:01。但是,当分钟或者秒钟的值小于10时,把分钟和秒钟的字符串连接起来将是1:1这样一个字符串。对于在线小测试程序,分钟数不会超过5,实际上只需直接在前面加上0即可。但是,为了使代码能适应未来需求发生的变化—— 例如允许用户回答问题的时间超过9分钟,则应使用if语句进行检查,以便确定分钟数是否小于10。
要修正格式问题,只需在分钟数或秒钟数小于10时,在其前面添加一个额外的0即可,相应代码如下所示:
if (minutes < 10)
minutes = "0" + minutes;
if (seconds < 10)
seconds = "0" + seconds;
最后,更新浏览器状态栏中剩余时间的显示:
window.status = "Time left is " + minutes + ":" + seconds;
在前面的这两个函数中,我们用到了几个新的全局变量。这些全局变量为:
var timeLeft =-1;
var totalQuestionsToAsk = 0;
var quizTimerId = 0;
请将上面全局变量的定义添加到脚本块的开始处。
最后,再对getQuestion()函数进行两处较小的修改,就能完成本章中小测试程序的修改。
首先,修改的是函数开始处的if语句:
if (totalQuestionsToAsk != numberOfQuestionsAsked)
{
var questionNumber = Math.floor(Math.random() * questions.length);
在上一版本的在线小测试程序中,只要可用的问题还没有问完,就可以继续提问。现在,当变量totalQuestionsToAsk的值不等于实际所问问题的数量时,则继续进行提问。totalQuestionsToAsk是一个全局变量,其中保存的是用户在下拉列表框中选中的问题的数量。在前面的代码中,用户选中的问题数量将作为参数传递给resetQuiz()函数,并在resetQuiz()函数中赋值给全局变量totalQuestionsToAsk。
第二个修改的地方是else子句。当小测试结束时,将把用户小测试结果的汇总信息输出到页面上。注意,在前面的resetQuiz()函数中,我们设置了一个计时器以监测剩余时间,当时间到点时就结束在线小测试程序。现在,当小测试程序结束时,应该使用clearInterval()方法清除该计时器。当计时器启动时,该计时器的ID号已经保存在全局变量quizTimerId中,只需将该计时器的ID号传递给clearInterval()方法,即可清除该计时器。另外,当用户并未设置答题的时限时,即用户未在cboTimeLimit下拉列表框中选择一个时限时,则timeLeft的值将为–1,这时,前面的resetQuiz()函数中并未设置任何计时器,因此,这里也就无须对计时器进行清除。为此,在下面的代码中,使用了if (timeLeft != –1)进行判断:
currentQNumber = questionNumber;
questionsAsked[questionNumber] = true;
}
else
{
if (timeLeft != -1)
{
clearInterval(quizTimerId);
}
questionHTML = "<h3>Quiz Complete</h3>";
questionHTML = questionHTML + "You got" + numberOfQuestionsCorrect;
到此为止,所有的修改都已经完成了。将上面修改后的代码保存为GlobalFunctions.htm文件。并在浏览器中加载TriviaQuiz.htm页面,以启动在线小测试程序。
如果修改后的代码正常,我们将看到一个如图9-8所示的页面。
图 9-8
如果在Time Limit下拉列表框中选择了一个时限,并单击Start Quiz按钮,则第一个随机抽取的问题将显示在页面上,并且计时器将开始倒计时,在浏览器的状态栏中将显示剩余的时间。
在Firefox浏览器和IE 7版本的浏览器中,通过JavaScript修改浏览器状态栏的功能在默认情况下是被禁止的。要在Firefox浏览器中打开该功能,只需选择Tools | Options,然后选择Content标签页。然后,单击Advanced Options按钮,然后选中Change Status Bar Text复选框。对于IE 7浏览器,只需选择Tools | Internet Options,然后再选择Security标签页。单击Internet,然后单击custom level,在打开的窗口中将滚动条下拉到Allow status bar updates via script复选框,并选中该复选框。
本章中对“在线小测试”程序的修改就到这里。在第11章中,我们将再次回到“在线小测试”程序,以介绍如何使用cookie将信息保存在用户的计算机上,以便提供一个前面所答题目信息的表格。