问题二:页面中倒计时结束时,请求到下一组数据渲染到页面,以及用户选择完正确答案之后请求到下一组数据渲染到页面

问题的关键在与,整个js文件中更新数据参数只有一个,且不管是答完题之后,还是答题超时,这个参数值是实时更新的

我的项目中需要是实现的功能是:在一个题目界面,有一个10秒倒计时,10秒计时结束后,用户没有答出题,那么久请求下一题的数据渲染到页面中。如果用户没有答题超时,那么用户在点击选择答案的时候,我们向后请求下一题的数据,然后将数据渲染到页面。

请求的路径地址是:http://localhost/testenglevel4/branch/server/public/getAnswerScore?questionId=1&studentId=1&answerId=1

我这里写的都是本地路径,产品上线时,就不能用本地路径了。

这其中就涉及到了题目的id值,无论是用户答题超时,还是用户选择了答案,题目的id是当前题目的id值加1。

(1)首先:在html页面,定义一个隐藏的标签来存储题目的id值

  

<input type="hidden" id="questionId" value={{$data["question"]->id}}/>

这里是用input设置类型为hidden,然后将题目的id值取出赋值给value值。

(2)定义一个10秒倒计时,在小于或等于0秒的时候,请求下一组数据值

其中questionId要定义为全局变量,10秒倒计时功能的实现主要是运用了setInterval函数,而将setInterval赋给timer,也必须定义为全局变量,因为在ajax请求的封装函数中,会用到清理定时器的情况。

//写在全局范围内
var timer = null;
var questionId;
questionId = $("#questionId").val();
//10秒倒计时,并在答题超时时,请求下一组数据
function RunTimer(num,questionId) {
  $("#time").text(num);//将时间数值num渲染到页面
  timer = setInterval(function (){ //定义匿名函数,      
    if(num <= 0){//首先判断num的值是不是<=0
      clearInterval(timer);//如果num的值<=0,那就表示时间到了,就要将现在的倒计时清除,不清除倒计时,会是后面的定时器时间越来越快。
      //下面是一个提示答题时间到了的遮罩层
      $("#mask").html('<div class="model">答题时间<br/>已结束</div> ');
      $("#mask").css("display","block");
      //10秒结束,用一个定时器,在一秒之后请求下一组数据。
      setTimeout(function(){
        //在请求的时候,出现一个请等待的模态框,增强用户体验
        $("#mask").html('<div class="loding"><img src="images/loding.gif"/></div>');
        $("#mask").css("display","block");
        //定义请求时需要的参数,其中studentId,answerId都被我写死了。实际中studentId是不写死的,然后规定用户答题超时时,给后台返回的answerId为-1
        var studentId = 1;
        var answerId = -1;
        var params = {
          questionId: questionId,
          studentId: studentId,
          answerId: answerId
        }
        //请求的路径,因为我是本地测试环境,所以url路径是同一个项目下的另一个文件。
        var urlRes = "getAnswerScore";
        //封装的ajax请求函数,这里定义一个传递的questionId的参数,是用来在ajax中重启定时器会用到的。
        responseWithNoCallback(urlRes,params,questionId);
      }, 1000);
    }else{//此时是num>0的情况,也就是还在倒计时时的情况
      num--;    //函数每调用一次num减一
      $("#time").text(num);
    }
  },1000);     //每隔一秒执行一次该匿名函数
}

(3)用户点击之后,发送请求。

//给ul下面的li绑定click事件
$("#answerWrap li").on("click",function(event){
    //用户一点击完,就要清除还在走的定时器
    clearInterval(timer);

    //这里是关键,取到存到隐藏的input中的题目的id值。
    questionId = $("#questionId").val();

    //获取用户点击的 event事件,保存点击的li的id值,用来后续的判断
    event = window.event || event || e;
    var target = event.target || window.event.srcElement;
    var id = target.id;
    //判断用户是否有选择
    if(id != '' || id != null){//这里是如果用户有点击的情况
        //给用户选择的li添加一个效果
        var targetLi = document.getElementById(id);
        targetLi.className = "active";
        //事先将answerId的值已经用data-属性存入了每个li中。
        //这里要注意data-属性的调用时,无论定义属性后缀有没有大写字母,获取值是都是小写字母
        var answerId = targetLi.dataset.answerid;
        //studentId 是写死的
        var studentId = 1;
        var urlRes = "getAnswerScore";
        //这里就将隐藏在input中的题目的id值,给了参数questionId。
        //这里要注意的是第一组题目的id是1,请求的链接是http://localhost/testenglevel4/branch/server/public/getAnswerScore?questionId=1&studentId=1&answerId=..
也就是说questionId=1获取了下一组数据。
        var params = {
          questionId: questionId,
          studentId: studentId,
          answerId: answerId
        }
        //请求之后,出现等待模态框
        $("#mask").html('<div class="loding"><img src="images/loding.gif"/></div>');
        $('#mask').css("display","block");
        responseWithNoCallback(urlRes,params,questionId);
        
      }
})

(4)现在,就是ajax 的封装装函数了

//ajax请求
function responseWithNoCallback(url, data, questionId) {
  var xhr = $.ajax({
      //提交数据的类型 POST GET
      type: "get",
      //提交的网址
      url: url,
      //提交的数据
      data: data,
      // 设置超时的时间20s
      timeout:20000,
      //返回数据的格式
      datatype: "json", //"xml", "html", "script", "json", "jsonp", "text".
      xhrFields: {
          withCredentials: true
      },
      crossDomain: true,
      //在请求之前调用的函数
      beforeSend: function () {

      },
      //成功返回之后调用的函数             
      success: function (response) {
        //在请求完成之后,li的选中的状态消失
         $("#answerWrap li").each(function(index, el) {
          if ($(this).hasClass('active')) {
            $(this).removeClass('active');
          }
        });
        //json数据解析的两种方法,建议用我用的这种,eval不安全
        // var response = eval("(" + response + ")");解析json数据
        var response = JSON.parse(response);
        var data = response.data;
        
        //这一块是数据渲染到页面,可以用不细究
        $(".question_title").text(data.nextQuestion.title);
        $("#audio").data("type",data.nextQuestion.type);
        //将音频资源链接加载到文档中,
        // $("player").attr("src",data.nextQuestion.audio);
        $("#optionOne").text(data.nextQuestion.answers[0].answer);
        $("#optionTwo").text(data.nextQuestion.answers[1].answer);
        $("#optionThree").text(data.nextQuestion.answers[2].answer);
        $("#optionFour").text(data.nextQuestion.answers[3].answer);
        $("#optionOne").data("answerId",data.nextQuestion.answers[0].id);
        $("#optionTwo").data("answerId",data.nextQuestion.answers[1].id);
        $("#optionThree").data("answerId",data.nextQuestion.answers[2].id);
        $("#optionFour").data("answerId",data.nextQuestion.answers[3].id);            
        
        //重点,这里是请求返回的数据中的question的Id值取出,并给到input的value中存储起来
        questionId = data.nextQuestion.id;
        $("#questionId").val(questionId);

     
        //到这新的数据已经渲染到页面了,那么请等待的模态框就可以消失了
        $("#mask").html('<div class="loding"><img src="images/loding.gif"/></div>');
        $('#mask').css("display","none");
        //在题目重新加载完的时候,重启倒计时,这是要把现在请求到哪题了,也就是这时题目的id值给到Runtime中请求时的questionId        
        RunTimer(3,questionId);
        //有值的传递就要将值return出去
        return questionId;
      },
      //调用执行后调用的函数
      complete: function (XMLHttpRequest, textStatus) {
        
      },
      //调用出错执行的函数
      error: function () {
          //请求出错处理
          console.log("error");

          //这里是请求出错,也就是已经将最后一组数据答完了,后面已经没有数据,就在同一个页面渲染答完题的页面
        $("#questionTest").css("display","none");
        $("#userInfo").css("display","block");
        $('#mask').css("display","none");
      }
  });
}

最重要是要明白,javascript是需要顺序执行的,其实看完了实现过程,会了解到,ajax请求中新添加的questionId传递给倒计时函数Runtime,是没必要的,还搞的很难理解,只需要在Runtime函数的请求之前,将input的value的值取到就可以了。

我为什么要保存这个步骤呢,是因为一开始我使用的传参的方法,去建立倒计时函数,onclick函数,ajax封装函数之间的联系,但是后来出现了bug.

之前onclick事件是这样写的,questionId的值一开始是1,这个对于一直都会进行选择的用户是没有问题的,但是对于有的题选择了,有的题答题超时的用户,就会出现questionId发生错乱的情况,因为,click事件中请求时传递的参数param中questionId值变化是1,2,3,4,5,6,7,8....是顺序变化的,而请求中的第三个参数questionId使用来传参给ajax请求中重启定时器的参数questionId,这就出现了参数变化不统一d的情况。

 var questionId = 1;//定义为全局变量
//用户点击选项后,将用户选择的答案返回给后台。
  $("#answerWrap li").on("click",function(event){
    clearInterval(timer);
      event = window.event || event || e;
      var target = event.target || window.event.srcElement;
      var id = target.id;

      //questionId = $("#questionId").val();//这句是关键,让全局只有一个统一变化的questionId

      if(id != '' || id != null){
        var targetLi = document.getElementById(id);
        targetLi.className = "active";
        var answerId = targetLi.dataset.answerid;
        var studentId = 1;
        var urlRes = "getAnswerScore";
        var params = {
          questionId: questionId,
          studentId: studentId,
          answerId: answerId
        }
        responseWithNoCallback(urlRes,params,questionId); 
        questionId++;  
      }    
  })

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值