Node.js在线考试系统——页面布局(学生)

Node.js在线考试系统

1.布局总览

准备界面.jpg
答题界面.jpg

2.页面布局模块分析

1.navBar

页面中的导航栏

2.ready

考试前的准备界面,由三个部分组成

  • 考试开始时间
  • 考试倒计时
  • 开始测试按钮
2.1 deltaTime

考试倒计时

2.2 startTest

开始测试按钮,时间到则允许开始考试

3.main

考试的主要界面,由四个部分组成

  • 题目相关信息
  • 题目内容
  • 输入框
  • 三个按钮
3.1questionInfo

题目相关信息,包括题目序号、题目分值、题目描述

3.2QuestionDetail

题目内容

3.3inputTe

答案输入框

3.4submit

由三个按钮组成,分别为切换到上一题、提交、切换到下一题

4.testInfo

考试相关信息,由两个部分组成

  • 欢迎信息,例:Welcome!TOM!
  • 题目编号,点击可跳转到相应题目

3.页面布局代码

准备界面

//省去html和body

考试10:00开始 //button的样式用的是Buttons这个库
html{
    height: 100%;
}
body{
    margin: 0;
    font-family: "Helvetica Neue",Helvetica,"Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
    height: 100%;
    -webkit-background-size: cover;
    background-size: cover;
    position: relative;
}
.navBar{
    position: absolute;
    top: 0;
    height: 80px;
    background: #FF6600;
    display: flex;
    justify-content: space-around;
    z-index: 1;
    min-width: 100%;
}
.navBar-Content{
    width: 1000px;
    height: inherit;
    display: flex;
    align-items: center;
    justify-content:space-between;
}
.navBar-Content span{
    color: #ffffff;
    font-weight: 900;
    font-size: 20px;
}
.bc{
    display: flex;
    width: 100%;
    position: relative;
    flex-direction: column;
    height: 100%;
    background: url(/images/bizhi1.jpg) no-repeat center;
    min-width:1000px;
    justify-content: space-around;
    min-height: 800px;
}
.ready{
    width: 300px;
    height: 300px;
    background: rgba(0,102,255,0.5);
    align-self: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-around;
}
.ready span{
    color: #ffffff;
    font-size: 20px;
}

答题界面

第一题 分值:20分 题目描述:
',
Welcome!TOM!
编号: 1 2 3 4 5
.main{
    padding:20px 50px 0 50px;
    width: 800px;
    display: flex;
    flex-direction: column;
    background: rgba(255,255,255,0.5);
    align-self: center;
    height: inherit;
    overflow-y: auto;
    margin-top: 80px;
}
.questionInfo{
    display: flex;
    flex-direction: column;
}
.questionInfo span{
    margin-top: 5px;
}
.QuestionDetail{
    background: #ffffff;
    opacity: 0.8;
    border: solid 1px #1B9AF7;

    font-size: 18px;
}
.inputTe{
    margin-top: 100px;
    border: solid 1px #999999;
    background:rgba(255,255,255,0.5);
    flex: 0 0 350px;
    word-break: break-all;
}
.submit{
    margin-top: 40px;
    display: flex;
    justify-content: center;
    justify-content:space-around;
    flex: 1 0 40px;
    padding-bottom: 20px;
    align-items: end;
}
.testInfo .submit{
    flex-direction: column;
    margin: 0;
    justify-content: space-around;
    height: 150px;
    flex: none;
    align-items: stretch;
}
.testInfo{
    position: fixed;
    right: -240px;
    top: 50%;
    transform: translate(0,-50%);
    width: 200px;
    background: rgba(0,0,0,0.3);
    transition: right 1.5s;
    display: flex;
    flex-direction: column;
    padding: 30px 20px;
}
.testInfo .welcome{
    color: #fff;
    display: flex;
    justify-content: center;
    font-size: 18px;
    align-items: center;
}
.selectNumber{
    margin-top: 20px;
    display: flex;
    flex-wrap: wrap;
    border: solid 1px #eee;
    justify-content: space-around;
    padding: 10px 0;
}
.coverLine{
    flex: 1 0 100%;
    padding-left: 15px;
}
.Number{
    margin-top: 10px;
    flex: 0 0 35px;
    display: flex;
    justify-content: center;
    cursor: pointer;
    background: #999999;
    height: 35px;
    align-items: center;
    border-radius: 17.5px;
}
.Number:hover{
    background: #bbbbbb;
}
.selectNumber span{
    font-size: 18px;
    color: #ffffff;
}

4.页面js代码

4.1准备界面:

用户登录到登录界面->创建modal()模块->modal()模块返回modalBox.init()函数,init()函数主要实现两个功能

1.计算出倒计时并渲染到界面上
2.绑定开始考试按钮的监听事件

var MODALBOX;
$(init);
function init() {
    MODALBOX = new modal();
}
var modal = function () {
    var ptrThis;
    var body = document.getElementsByTagName('body'); //body
    var questionInfo = document.getElementsByClassName("questionInfo");//题号+分值+(题目描述)
    var QuestionDetail = document.getElementsByClassName("QuestionDetail");//题目详细内容
    var testInfo = document.getElementsByClassName("testInfo");//右侧题目选择框
    var modalBox = {
        calculTime:function () {},
        bindStartTest:function () {},
        init:function () {
            ptrThis = this;
            ptrThis.calculTime();   //准备考试界面的倒计时
            ptrThis.bindStartTest();//绑定开始考试按钮的监听事件
        }
    }
    return modalBox.init();
}

计算考试倒计时

        calculTime:function () {
            var deltaTime = document.getElementById("deltaTime");
            var goal = new Date("2016-11-28 22:00:00");//暂时没有实现后台功能,先用本地时间
            var now = new Date();//调用js的Date类来获取时间
            var deltaTotalTime = (goal.getTime()-now.getTime())/1000;//getTime以毫秒为单位,所以需要/1000才能获得秒
            var deltaHours = Math.floor(deltaTotalTime/3600);//小时
            var deltaMinutes = Math.floor((deltaTotalTime-3600*deltaHours)/60);//分钟
            var deltaSeconds = Math.floor(deltaTotalTime-deltaHours*3600-deltaMinutes*60);//秒
            deltaTime.textContent = "时间还剩"+deltaHours+"小时"+deltaMinutes+"分钟"+deltaSeconds+"秒";
            setInterval(function () {//没过一秒重新设置一次
                now = new Date();
                deltaTotalTime = (goal.getTime()-now.getTime())/1000;
                deltaHours = Math.floor(deltaTotalTime/3600);
                deltaMinutes = Math.floor((deltaTotalTime-3600*deltaHours)/60);
                deltaSeconds = Math.floor(deltaTotalTime-deltaHours*3600-deltaMinutes*60);
                deltaTime.textContent = "时间还剩"+deltaHours+"小时"+deltaMinutes+"分钟"+deltaSeconds+"秒";
            },1000)
        }

绑定开始考试按钮的监听事件bindStartTest

bindStartTest:function () {
            var startTest = document.getElementById("startTest");
            startTest.addEventListener('click',function () {
                var bc = document.getElementsByClassName("bc");//bc为界面的背景
                var content = [
                    '
', '
', ' 第一题', ' 分值:20分', ' 题目描述:', '
', ' ', ' ', '
', '
', ' ', ' ', ' ', '
', '
' ].join(""); //通过getElementsByClassName获取到的dom元素返回的是数组,所以需要通过下标[0]来获取实际需要的元素 //页面采用js动态渲染,将bc原来的准备界面清空,然后将字符串转换为html重新给bc[0].innerHTML赋值 bc[0].innerHTML = content; ptrThis.startTest();//将一系列监听事件绑定至界面元素 }); }

4.2答题界面:

用户点击GO触发按钮startTest的点击事件->渲染界面->ptrThis.startTest()->将一系列事件绑定,startTest实现的功能:

1.绑定输入框的监听事件
2.将题目选择框弹出
3.绑定选择问题监听事件
4.绑定上一题、提交、下一题按钮

var MODALBOX;
$(init);
function init() {
    MODALBOX = new modal();
}
var modal = function () {
    var ptrThis;
    var body = document.getElementsByTagName('body'); //body
    var questionInfo = document.getElementsByClassName("questionInfo");//题号+分值+(题目描述)
    var QuestionDetail = document.getElementsByClassName("QuestionDetail");//题目详细内容
    var testInfo = document.getElementsByClassName("testInfo");//右侧题目选择框
    var modalBox = {
        default:{
              questions:[{
                  question:"读入一个自然数n,计算其各位数字之和,用汉语拼音写出和的每一位数字。",
                  score:20,
                  Chinese:"一"
              },{
                  question:"读入n名学生的姓名、学号、成绩,分别输出成绩最高和成绩最低学生的姓名和学号。",
                  score:15,
                  Chinese:"二"
              },{
                  question:"设计函数求一元多项式的导数。(注:xn(n为整数)的一阶导数为n*xn-1。)",
                  score:25,
                  Chinese:"三"
              },{
                  question:"月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不同风味的月饼。现给定所有种类月饼的库存量、总售价、以及市场的最大需求量,请你计算可以获得的最大收益是多少。",
                  score:20,
                  Chinese:"四"
              },{
                  question:"为了用事实说明挖掘机技术到底哪家强,PAT组织了一场挖掘机技能大赛。现请你根据比赛结果统计出技术最强的那个学校。",
                  score:20,
                  Chinese:"五"
              }],
              index:0//当前题目编号,
        },
        bindTextArea:function () {},
        showTestInfo:function () {},
        bindSelectQuestion:function () {},
        bindButton:function () {},
        toggleQuestion:function () {},
        startTest:function () {
            ptrThis.bindTextArea();//绑定输入框的监听事件
            ptrThis.showTestInfo();//将题目选择框弹出
            ptrThis.bindSelectQuestion();//绑定选择问题监听事件
            ptrThis.bindButton();//绑定上一题、提交、下一题按钮
        }
    }
    return modalBox.init();
}

绑定输入框的监听事件bindTextArea

该监听事件实现了当输入框代码行数太多时,页面下面的三个按钮会移动到testInfo模块上的功能,触发条件为
questionInfo(问题信息框)+QuestionDetail(问题内容框)+inputTe(输入框)+200的高度>main(外部框架)高度

  bindTextArea:function () {
            var inputTe = document.getElementsByClassName("inputTe");//输入框
            var main = document.getElementsByClassName("main");//外部框架
            var bindEvent = ["paste","keyup","keydown","resize"];//输入框需要监听粘贴,键盘升起,按下,输入框大小发生改变四个事件
            var submit = document.createElement("div");//新建submit
            submit.classList.add("submit");//添加submit类
            submit.innerHTML =  ['       ',
                '',
                ''].join("");
            for (var i = 0;imain[0].clientHeight){
                        if(main[0].querySelector(".submit")!==null){
                            main[0].removeChild(main[0].querySelector(".submit"));
                            testInfo[0].appendChild(submit);
                        }
                    }else{
                        if(main[0].querySelector(".submit")===null){
                            main[0].appendChild(submit);
                            testInfo[0].removeChild(testInfo[0].querySelector(".submit"));
                        }

                    }
                })
            }
        }

演示

输入框监听事件.gif

绑定选择问题监听事件bindSelectQuestion

这个事件如果通过jQuery来实现就是$("body").on("click",".Number",function(){});将事件绑定到body元素的好处是通过冒泡机制实现事件委托,不用担心元素发生改变后绑定事件失效的问题.详见http://www.cnblogs.com/aaronjs/p/3440647.html

        bindSelectQuestion:function () {
            body[0].addEventListener("click",function (e) {
                if(e.target.classList.contains("Number")){
                    //调用indexOf获取当前点击对象位于父节点的子节点序列中的下标
                    ptrThis.default.index = [].indexOf.call(e.target.parentNode.children,e.target)-1;
                    //因为改变题目内容有很多地方用到,所以直接设置为一个函数
                    ptrThis.toggleQuestion();
                }
            },false);
        },

重新设置题目相关数据函数toggleQuestion

这个函数修改了questionInfoQuestionDetail两部分的内容

        toggleQuestion:function () {
            questionInfo[0].children[0].textContent="第"+ptrThis.default.questions[ptrThis.default.index].Chinese+"题";
            questionInfo[0].children[1].textContent="分值:"+ptrThis.default.questions[ptrThis.default.index].score;
            QuestionDetail[0].textContent=ptrThis.default.questions[ptrThis.default.index].question;
        },

绑定上一题、提交、下一题按钮监听事件bindButton

同样的事将监听事件绑定到body元素,然后通过getAttribute方法获取相应的id值来判断是哪一个按钮的点击事件

        bindButton:function () {
            body[0].addEventListener("click",function (e) {
                var ID = e.target.getAttribute("id");
                switch (ID){
                    case "preQuestion":
                        ptrThis.default.index = ptrThis.default.index==0?0:ptrThis.default.index-1;
                        break;
                    case "submit":
                        return;//还未实现与服务器后台的功能
                    case "nextQuestion":
                        ptrThis.default.index = ptrThis.default.index==4?4:ptrThis.default.index+1;
                        break;
                    default:
                        break;
                }
                ptrThis.toggleQuestion();
            },false);
        }

5.心得

新项目新思路,尝试用原生的js来完成各种功能虽然遇到了很多坑,但也收获到了不少知识.

你可能感兴趣的:(Node.js在线考试系统——页面布局(学生))