在微信小程序中的 答题系统。

前言

        在我们的开发中,可能需要编写一个答题模板,那这个文章简单地粗略地介绍了答题系统的主要功能和ui页面。

1.页面结构

        一般来说,答题系统需要我们写编写三个页面,包括介绍页,答题页,结果页。

        介绍页:一般有答题的介绍,题目数,题目内容等待。

        答题页:一般有单选多选判断分类,题目数和当前题目序号,进度条,倒计时或者计时,题目标题和答案选项。

        结果页:一般有对错题目数,正确率,用时,可能包括错题解析。

2.介绍页

<view class="intro_page" wx:if="{{progressFlag==1}}">
  <view class="title">{{title}}</view>
  <view class="intro_page__container">
    <view>活动介绍</view>
  </view>
  <button class="around_btn theme_btn" style="width: 200rpx;" hover-class="btn_hover" bindtap="onChangeProgressFlag">进入答题</button>
</view>

这里将3个页面集合到了1个页面中,用progressFlag代表页面的进度。

title指的是答题系统的标题,比如说xxx届答题大赛。

onChangeProgressFlag函数就是修改progressFlag,并且获取答题题目。

  onChangeProgressFlag() {
    this.getQuestion()
    this.setData({
      progressFlag: 2,
      // startTime: dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss')
    })

可以在前端获取答题时间,也可以通过后端服务器时间保存到数据库中(此内容根据需求来定)

3.答题页

此部分为最难的部分,因为需要渲染题目和选项,这里通过跟后端协商来确定api数据的格式。

一般用对象数组表示。

const questionList=[
{id:123,questionType:1,question:'吴彦祖和郭富城谁帅?',optionArr=['郭富城','吴彦祖','博主本人']},
{id:234,questionType:2,question:'吴彦祖和郭富城谁帅?',optionArr=['郭富城','吴彦祖','博主本人']},
{id:345,questionType:3,question:'吴彦祖比郭富城帅?',optionArr=['是','不是']}
]

这里用id区分不同的问题,questionType代表答题的类型,1代表单选,2代表多选,3代表判断。

question代表答题的问题,optionArr代表选项。

let list = []
            res.data.result.forEach(item => {
              list.push({
                id: item.id,
                title: item.question,
                answerList: item.optionArr,
                answerType: item.questionType
              })
            })
            this.setData({
              questionList: list,
              _maxStep: res.data.result.length
            })

在getQuestion函数中设置如上,将api获取的数据保存到data对象中。

<view class="quiz_page" wx:if="{{progressFlag==2}}">
  <!-- 答题页 -->
  <view>
    <view style="text-align: center;line-height: 100rpx;display: flex;justify-content: space-between;">
      <view>
        <text>{{step}}<text style="color:gray;font-weight: 500;">/{{_maxStep}}题</text></text>//这里是显示当前序号和总题数
      </view>
      <view>
        <t-count-down auto-start format="mm:ss" time="{{time}}" splitWithUnit size="large" t-class="count-down" t-class-count="count-down__item" bind:finish="quizTimeOut" bind:change="onChangeCountdown"></t-count-down>
      </view>//这里利用tdesign的count-down组件实现倒计时
    </view>
    <progress percent="{{step/_maxStep*100}}" activeColor="var(--theme-color)" style="margin:0 0 32rpx 0;" />//这里是进度条
    <view>

    //以下代码为题目的html代码
      <view class="question">
        <text style="margin-right: 16rpx;">[{{questionList[step-1].answerType==1?'单选题':(questionList[step-1].answerType==2?'多选题':'判断题')}}]</text>{{step}}.{{questionList[step-1].title}}
      </view>
//此部分为单选渲染渲染
      <view class="option" wx:if="{{questionList[step-1].answerType=='1'}}">
        <view wx:for="{{questionList[step-1].answerList}}" wx:key="index" style="display: flex;align-items: center;margin: 8rpx 0;" data-value="{{index}}" bind:tap="onChangeButtonIndex">
          <view class="option__orderNumber {{buttonIndex==index?'theme_btn':''}}">
            {{_orderNumberList[index]}}</view>
          <view class="{{buttonIndex==index?'option__selected':''}}" style="width: 600rpx;text-align: left;">{{item}}</view>
        </view>
      </view>
    //此部分为多选选项渲染
      <view class="option" wx:if="{{questionList[step-1].answerType=='2'}}">
        <view wx:for="{{questionList[step-1].answerList}}" wx:key="index" style="display: flex;align-items: center;margin: 8rpx 0;" data-value="{{index}}" bind:tap="onChangeMultiButtonIndex">
          <view class="option__orderNumber {{multiButtonIndex[index]==1?'theme_btn':''}}">
            {{_orderNumberList[index]}}</view>
          <view class="{{multiButtonIndex[index]==1?'option__selected':''}}" style="width: 600rpx;text-align: left;">{{item}}</view>
        </view>
      </view>
    //此部分为判断渲染渲染
      <view class="option" wx:if="{{questionList[step-1].answerType=='3'}}">
        <view style="display: flex;align-items: center;margin: 8rpx 0;" data-value="1" bind:tap="onChangeTrueOrFalse">
          <view class="option__orderNumber {{TFButtonIndex==1?'theme_btn':''}}">A</view>
          <view class="{{TFButtonIndex==1?'option__selected':''}}" style="width: 600rpx;text-align: left;">正确</view>
        </view>
        <view style="display: flex;align-items: center;margin: 8rpx 0;" data-value="0" bind:tap="onChangeTrueOrFalse">
          <view class="option__orderNumber {{TFButtonIndex==0?'theme_btn':''}}">B</view>
          <view class="{{TFButtonIndex==0?'option__selected':''}}" style="width: 600rpx;text-align: left;">错误</view>
        </view>
      </view>
    </view>
    <view>
      <button style="margin-bottom: 100rpx;" class="theme_btn" hover-class="btn_hover" bindtap="nextQuestionOrCommit">下一题</button>
    </view>
  </view>
</view>

这里通过{{questionList[step-1].answerType==1?'单选题':(questionList[step-1].answerType==2?'多选题':'判断题')}} 来显示题型。

 wx:if="{{questionList[step-1].answerType=='1'}}"判断题目类型。

wx:for="{{questionList[step-1].answerList}}"渲染出选项。

buttonIndex、multiButtonIndex、TFButtonIndex都表示被点击的按钮索引,默认值为-1、{}、-1。

onChangeButtonIndex(e) {
    let val = e.currentTarget.dataset.value
    this.setData({
      buttonIndex: val
    })
  },
  onChangeMultiButtonIndex(e) {
    let val = e.currentTarget.dataset.value
    let list = this.data.multiButtonIndex
    if (list[val] && list[val] == 1) {
      list[val] = 0
    } else {
      list[val] = 1
    }
    this.setData({
      multiButtonIndex: list
    })
    setTimeout(() => {
      this.data.multiButtonIndex.indexOf(val)
    }, 0);
  },
  onChangeTrueOrFalse(e) {
    let val = e.currentTarget.dataset.value
    this.setData({
      TFButtonIndex: val
    })
  },

对于多选的button点击事件,这里是用对象的形式表示,键为0、1、2等等,值为0或1。

  nextQuestionOrCommit() {
    if (Object.keys(this.data.multiButtonIndex).length == 0 && this.data.buttonIndex == -1 && this.data.TFButtonIndex == -1) {
      wx.showToast({
        title: '必须选择选项后才可以进行下一题',
        icon: 'none',
        duration: 2000
      })
      return
    }
    if (this.data.buttonIndex != -1) {
      let list = this.data.answerList
      let obj = {}
      obj.id = this.data.questionList[this.data.step - 1].id
      obj.answer = String.fromCharCode(65 + Number(this.data.buttonIndex))
      obj.seq = this.data.step
      list.push(obj)
      this.setData({
        answerList: list
      })
    } else if (this.data.multiButtonIndex.length > 0) {
      let list = this.data.answerList
      let obj = {}
      obj.id = this.data.questionList[this.data.step - 1].id
      obj.seq = this.data.step
      let str = ''
      for (let i in this.data.multiButtonIndex) {
        let word = String.fromCharCode(65 + Number(i))
        str = str + word
      }
      obj.answer = str
      list.push(obj)
      this.setData({
        answerList: list
      })
    } else if (this.data.TFButtonIndex != -1) {
      let list = this.data.answerList
      let obj = {}
      obj.id = this.data.questionList[this.data.step - 1].id
      obj.answer = Number(this.data.TFButtonIndex)
      obj.seq = this.data.step
      list.push(obj)
      this.setData({
        answerList: list
      })
    }
    if (this.data.step < this.data._maxStep) {
      this.setData({
        buttonIndex: -1,
        multiButtonIndex: [],
        TFButtonIndex: -1,
        step: this.data.step + 1
      })
    } else {
      this.saveAnswer()
      this.setData({
        progressFlag: 3
      })
    }
    // console.log(this.data.answerList);
  },

这里先判断是否选择了选项,没选择择提示。

之后判断哪个index变化了,变了的index则将数据储存在一个list中,用于传递给后端。

如果step>maxstep(step为当前页面步数,每次下一步则+1,maxstep通过后端给的list.length得到),则进行提交api操作。

3.结果页

结果页一般是通过后端返回的数据渲染。

这里就不多赘述。

4.结语

希望在看完这边不太成熟的文章的观众们说一下谢谢,如果有问题可以直接在评论区发表评论。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值