65.9K
CodeProject 正在变化。 阅读更多。
Home

面向对象的 JavaScript 测验

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.13/5 (6投票s)

2006年10月16日

CPOL

3分钟阅读

viewsIcon

67062

downloadIcon

11

面向对象 JavaScript 测验,可以轻松自定义以添加更多功能。

引言

这基本上是我创建的动态 JavaScript 测验的日志。它广泛使用了 JavaScript 的面向对象特性。任何对 JavaScript 中真正高级的东西感兴趣的人都可以从该应用程序中使用的方法中学到很多东西。从头开始做这件事花了我大约两天的时间。

这个应用程序做什么?它允许某人添加任意数量的模块,其中包含任意数量的问题以及任意数量的选项。所有这些都在不编辑核心文件的情况下完成。也可以用 AJAX 调用替换 *questions.js*....

这是什么类型的测验?这是一个多项选择测验。

文件结构

  • index.html - 加载到浏览器中并显示测验的文件。
  • quiz.js - 包含核心测验功能的 JavaScript 代码文件。
  • test.js - 包含核心界面功能的 JavaScript 代码文件。
  • quiz.css - 包含控制测验的视觉元素(如字体和颜色)的指令的层叠样式表文件。
  • questions.js - JavaScript 代码文件,可以使用特定语法添加问题。

Index.html

我知道它看起来不多,但信不信由你,这就是将所有东西结合在一起的东西

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Quiz</title>
<script type="text/javascript" src="quiz.js"></script>
<script type="text/javascript" src="questions.js"></script>
<script type="text/javascript" src="test.js"></script>
<link rel="stylesheet" href="quiz.css" />
</head>
 
<body onLoad="displayset(0,0)">
<form name="submitquestions" action="index.html" method="get">
<div id="headdiv" class="layout">
<h1>
QUIZ: 
<script>
document.writeln(quiz1.name)
</script>
</h1>
</div>
 
<div id="modulediv" class="layout" >
<table align="center"><tr>
<script>
 
 
totalmodules = quiz1.total()
for(i = 0;i < totalmodules;i++)
{
    currentmodule = quiz1.get(i)
    document.writeln('<td class="module" cellspacing=0>')    
    totalsets = currentmodule.total()
    for(x=0;x<totalsets;x++)
    {
        currentset = currentmodule.get(x)
        document.writeln('<a href="javascript:displayset('+ i +','+ x +')">'+ 
             currentmodule.name +'(' + currentset.name + ')</a>|<br>')
 
    }
    document.writeln('</td>')
}
 
</script>
</tr></table>
</div>
<div id="sectionheader" class="layout">
<h3 id="hl"> </h3>
</div>
 
<div id="bodydiv" class="layout">
</div>
<div id="footer" class="layout">
<input type="button" onclick="displayresults()" value="Submit" />
</div>
</form>
</body>
</html>

quiz.js

您可以将此文件称为应用程序的大脑。这是定义应用程序中使用的所有对象类的地方。

/* *************************************************************************
GLOBALS AND UTILITY FUNCTIONS
Purpose of utility functions are to allow 
a novice user to add questions to questions.js
without having to worry about naming objects
**************************************************************************/
var globalmodule
var globalset
var globalquiz //really not necessary but put for completeness
var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
function nextmodule(name)
{
    globalquiz.add(name)
}
function nextset(name)
{
    globalmodule.add(name)
}
function addproblem(question,answer)
{
    globalset.add(arguments) 
}
 
/* ***********************************************************************
MAIN QUIZ class
**************************************************************************/
function quiz(name)
{
    this.right = 0
    this.wrong = 0
    this.name = name
    this.modules = new Array()
}
quiz.prototype.add = function(name)
{
    this.modules.push(new module(name)) 
    globalmodule = this.modules[this.modules.length-1]
}
quiz.prototype.get = function(module)
{
    return this.modules[module] 
}
quiz.prototype.total = function()
{
    return this.modules.length 
}

/* *********************************************************************
MODULE CLASS
************************************************************************/
function module(name)
{
    this.name = name
    this.sets = new Array()
}
module.prototype.add = function(name)
{
    this.sets.push(new set(name))
    globalset = this.sets[this.sets.length-1]
}
module.prototype.get = function(set)
{
    return this.sets[set] 
}
module.prototype.total = function()
{
    return this.sets.length 
}
/*******************************************************************
SET CLASS
********************************************************************/
function set(name)
{
    this.name = name
    this.rightanswers = 0
    this.problems = new Array()
}
set.prototype.add = function(args)
{
    this.problems.push(new problem(args)) 
}
set.prototype.get = function(problem)
{
    return this.problems[problem] 
}
set.prototype.total = function()
{
    return this.problems.length 
}
/*****************************************************************
SETUP QUESTIONS AND ANSWERS
PROBLEM CLASS
******************************************************************/
function problem(args)
{
    this.choices = new Array() 
    this.selection = -1 //have not chosen an answer
    this.question = args[0]
    this.answer = chars.indexOf(args[1])
    for (var i = 2; i < args.length; i++) 
    {
        this.choices.push(args[i])
    }
}
problem.prototype.totalchoices = function()
{
    return this.choices.length 
}
problem.prototype.getchoice = function(choice)
{
    return this.choices[choice] 
}

Test.js

该文件包含动态渲染测验的代码,它基于 *questions.js* 的内容使用来自 quiz.js 的例程,我将在下面展示。

/********************************************** JavaScript Document
Interface functions responsible for displaying 
quiz elements and general flow of quiz
*******************************************************************/
 
function displayset(module,set)
{
    getmodule = quiz1.get(module)
    getset = getmodule.get(set)
    globalset = getset

    //set subheader for set
    var sheader = document.getElementById('hl')
    headertext = getmodule.name + " - " + getset.name + 
                 ": Answer the following questions"
    sheader.childNodes[0].nodeValue = headertext

    // clear questions
    questionsdiv = document.getElementById('bodydiv')
    if(questionsdiv.childNodes)
    {
        for(var i = 0;i<questionsdiv.childNodes.length;i++)
        {
            questionsdiv.removeChild(questionsdiv.childNodes[i]) 
        }
    }
    //write out questions and choices for current selected set
    totalproblems = getset.total()
    questionlist = document.createElement('OL')

    for(var i=0;i<totalproblems;i++)
    {
        currentproblem = getset.get(i)
        listitem = document.createElement('LI')
        questionbreak = document.createElement('BR')
        listquestion = document.createTextNode(currentproblem.question)

        //list choices for current problem
        choicelist = document.createElement('UL')

        uniqueid = uniquename(5)
        totalchoices = currentproblem.totalchoices()
        for(var x = 0;x < totalchoices;x++)
        {
            choiceitem = document.createElement('LI') 
            listradio = document.createElement('INPUT')
            listradio.setAttribute('type','radio')
            listradio.setAttribute('onClick', 
              'selectoption('+module+','+set+','+i+','+x+')')

            listradio.setAttribute('name',uniqueid)
            listradio.setAttribute('value',uniqueid) 
            choiceitemchar = document.createTextNode(chars.charAt(x) + ". ")
            choiceitemtext = 
               document.createTextNode(currentproblem.getchoice(x))
            choiceitem.appendChild(listradio)
            choiceitem.appendChild(choiceitemchar)
            choiceitem.appendChild(choiceitemtext)
            choicelist.appendChild(choiceitem)
        }
        listitem.appendChild(listquestion)
        listitem.appendChild(choicelist)
        questionlist.appendChild(listitem)
    }
    questionsdiv.appendChild(questionlist) 
    iefix()
}
function selectoption(module,set,problem,roption)
{
    //alert(module +"/"+ set +"/"+ problem +"/"+ roption)
    getmodule = quiz1.get(module)
    getset = getmodule.get(set)
    getproblem = getset.get(problem)
    getproblem.selection = roption
}
function uniquename(length)
{
    name = "";
    for(x=0;x<length;x++)
    {
        i = Math.floor(Math.random() * 52);
        name += chars.charAt(i);
    }
    return name;
}
function displayresults()
{
    //alert(document.getElementById('bodydiv').innerHTML)
    var noanswer = new Array()
    globalset.rightanswers = 0
    for(var i = 0;i<globalset.total();i++)
    {
        getproblem = globalset.get(i)
        if(getproblem.selection == -1)
        {
            noanswer.push(i + 1)
        }
        if(getproblem.selection == getproblem.answer)
        {
            globalset.rightanswers++ 
        }
    }
    switch(noanswer.length)
    {
        case 0 :
            percentage = Math.round(100 * 
                        (globalset.rightanswers/globalset.total()))
            //totalwrong = (globalset.total() - globalset.rightanswers)
            var resultstring = globalmodule.name +' - '+ globalset.name + '\n\n'
            resultstring+= 'Your Score is ' + percentage + '%'
            resultstring+= ' ('+ globalset.rightanswers+'/'+ globalset.total() +')\n\n'
            resultstring+= 'Question Your Answer Correct Answer Result \n'
            for(var x=0;x<globalset.total();x++)
            {
                question = x+1
                getproblem = globalset.get(x)
                resultstring+=' '+ question + ' '
                resultstring+=chars.charAt(getproblem.selection) + ' '
                resultstring+=chars.charAt(getproblem.answer) + ' '
                resultstring+= 
                  (getproblem.selection == getproblem.answer)? 'o\n':'x\n'
            }

            alert(resultstring);
            break;
        default :
        var noanswerstring =""
        for(var j=0;j<noanswer.length;j++)
        {
            noanswerstring += 'Question (' + noanswer[j] + ')\n' 
        }
        alert("The follwoing questions were not answered:\n\n" + noanswerstring)
    }
}

/*****************************************************************************
Function created to address issue with internet explorer after experiencing 
problems dynamically setting the name attribute of radio buttons. 
N.B. Other browsers don't need this.
******************************************************************************/
function iefix()
{
    if(document.all)
    {
        rawdata = document.getElementById('bodydiv').innerHTML
        fixdata = rawdata.replace(/value/g,"name")
        document.getElementById('bodydiv').innerHTML = fixdata
    }
}

questions.js

以下是显示如何添加问题的简单示例。虽然当前 index.html 页面是为名为 quiz1 的单个测验硬编码的,但可以定义多个测验。

按照这些说明添加新模块、集合和问题

  1. 要添加新模块,只需输入:nextmodule('模块名称')。“模块名称”将显示在模块选择中。
  2. 要添加新集合,只需输入:nextset('集合名称')。“集合名称”将显示在集合选择中。
  3. 要添加问题,请观察以下模式:addproblem("你的问题",正确答案的位置,"答案1","答案2","答案3" 等。)
var quiz1 = new quiz('Sample Name')
globalquiz = quiz1
nextmodule('m1')
nextset('set 1')
addproblem("How old are you",'a',"10 to 13 years","14 to 20 years","21 to 25 years")
addproblem("your birth month?",'c',"Jan","mar","may","jul","dec")
addproblem("How old are you",'b',"10 to 13 years","14 to 20 years","21 to 25 years")
nextset('set 2')
addproblem("How old are you",'a',"10 to 13 years","14 to 20 years","21 to 25 years")
addproblem("your birth month?",'a',"Jan","mar","may","jul","dec")
addproblem("How old are you",'b',"10 to 13 years","14 to 20 years","21 to 25 years")
addproblem("your birth month?",'d',"Jan","mar","may","jul","dec")
nextmodule('m2')
nextset('set 1')
addproblem("How old are you",'b',"10 to 13 years","14 to 20 years","21 to 25 years")
addproblem("your birth month?",'b',"Jan","mar","may","jul","dec")
addproblem("How old are you",'a',"10 to 13 years","14 to 20 years","21 to 25 years")
addproblem("your birth month?",'c',"Jan","mar","may","jul","dec")
nextset('set 2')
addproblem("How old are you",'c',"10 to 13 years","14 to 20 years","21 to 25 years")
addproblem("your birth month?",'b',"Jan","mar","may","jul","dec")
addproblem("How old are you",'b',"10 to 13 years","14 to 20 years","21 to 25 years")
addproblem("your birth month?",'d',"Jan","mar","may","jul","dec")

quiz.css

可以修改此文件以更改测验元素的外观和风格。

/* CSS Document */
div.layout { margin:0px 0px 0px 0px; }
#modulediv { text-align:center; padding:0px 0px 0px 0px; }
#headdiv { text-align:center ; }
td.module { max-width:80px;}
#bodydiv { overflow:scroll;height:350px; max-height:350px; 
           overflow-x:hidden;border:thin inset black;}
#footer{text-align:center;}
body {margin-top:0px;}
#sectionheader {padding:0px 0px 0px 10px;}
ul {list-style-type:none;}

可以在这里看到此脚本的实际效果。

最终评论

这背后的想法是获取测验数据并

  1. 动态创建用户参加测验所需的界面。
  2. 提供有关用户选择的信息并将它们发送回去进行验证。

因此,给定面向对象的结构,也可以从另一个来源加载测验数据,而无需进行任何更改。例如,假设您的测验存储在 XML 文件中。您可以添加自己的 xml_question_reader.js,然后在 questions.js 中说以下内容

xml_test_source = load_xml_source_tree("path/to/quiz.xml")

for(x in xml_test_source.modules)
{
    xml_module = xml_test_source.modules[x]
    nextmodule(xml_module.name)

    for(y in xml_module.sets)
    {
        xml_set = xml_module.sets[y]
        nextset(xml_set.name)

        for(z in xml_set.problems)
        {
           xml_problem = xml_set.problems[z]
           addproblem(xml_problem.question,xml_problem.answer,xml_problem.options)
        }
    }
}

重要的是要注意,XML 源也可以由任何服务器端语言生成。但是,可能需要稍微更改脚本,因此您不必在初始化问题时在 JavaScript 中提供正确的答案。

此脚本演示了许多关键概念,包括将表单元素动态添加到页面,并且已经在 IE、Opera 和 Firefox 中进行了测试。 享受。

注意:之前的脚本没有真正的错误测试,应该仅用于教育目的。
© . All rights reserved.