開發(fā)答題微信小程序詳細(xì)記錄(附源碼)

前言:這幾天在公司閑閑無事,恰好團(tuán)隊(duì)有通過在線考試的需求岁经,于是自發(fā)擼了一個(gè)簡單的考試類微信小程序。 純前端蛇券,數(shù)據(jù)寫好在data.json文件里缀壤,每一次考試結(jié)果利用緩存存儲(chǔ)。

一纠亚、 試題數(shù)據(jù)

新建小程序項(xiàng)目時(shí)塘慕,我們看到已經(jīng)有index和logs頁,先不要管他蒂胞。我們新增一個(gè)和pages文件夾同級的data文件夾图呢,新建json.js文件存放我們的數(shù)據(jù)。

1. 數(shù)據(jù)格式:

// data/json.js
var json = {
    "001": [
        {
          "question": "爸爸的爸爸叫什么?",
          "option": {
            "A": "爺爺",
            "B": "姥爺",
            "C": "叔叔",
            "D": "伯伯",
            "E": "阿姨",
            "F": "老舅"
          },
          "true": "A",   // 正確答案
          "type": 1,     // 類型 1 單選  2 多選
          "scores": 10,  // 分值
          "checked": false  // 默認(rèn)沒有選中
        },
        {
          "question": "媽媽的姐妹叫什么?",
          "option": {
            "A": "姥姥",
            "B": "奶奶",
            "C": "叔叔",
            "D": "大姨",
            "E": "小姨",
            "F": "老舅"
          },
          "true": ["D", "E"],   // 正確答案
          "type": 2,     // 類型 1 單選  2 多選
          "scores": 10,  // 分值
          "checked": false  // 默認(rèn)沒有選中
        },
        ... ...
    ],
    "002": [
        // ...數(shù)據(jù)格式同上
    ]

}

2. 導(dǎo)出數(shù)據(jù)

// data/json.js

var json = {...}

module.exports = {
  questionList: json
}

定義完數(shù)據(jù)后骗随,要在json.js最后面使用module.exports導(dǎo)出蛤织。

3. 導(dǎo)入數(shù)據(jù)

// app.js

// 導(dǎo)入數(shù)據(jù)
var jsonList = require('data/json.js');

App({
  globalData: {
    questionList: jsonList.questionList  // 拿到答題數(shù)據(jù)
  }
})

在app.js里使用require導(dǎo)入數(shù)據(jù),并且定義在全局變量globalData里鸿染。將來使用的時(shí)候:

首先 var app = getApp();
然后 app.globalData.questionList 就可以拿到導(dǎo)出的json數(shù)據(jù)瞳筏。

因?yàn)槲覀儾恢挥幸惶自嚲恚懊嬖趈son里定義了兩個(gè)數(shù)組:001和002牡昆。之后可以通過
app.globalData.questionList["001"]選擇性導(dǎo)入試題數(shù)據(jù)姚炕。

二、 home頁面(考試入口)

在pages文件夾里新增home頁面丢烘。首頁授權(quán)登錄后點(diǎn)擊跳轉(zhuǎn)到該頁面柱宦,頁面上有兩個(gè)模塊:001和002。點(diǎn)擊模塊進(jìn)行對應(yīng)的考試播瞳。

1. 主要代碼

home.wxml

<view class="page">
  <view class="page-title">請選擇試題:</view>
  <view class="flex-box">
    <view class="flex-item"><view class="item bc_green" bindtap="toTestPage" data-testId="001">001</view></view>
    <view class="flex-item"><view class="item bc_red" bindtap="toTestPage" data-testId="002">002</view></view>
  </view>
</view>

home.js

Page({
  data: {

  },
  onLoad: function (options) {

  },
  toTestPage: function (e) {
    let testId = e.currentTarget.dataset['testid'];
    wx.navigateTo({
      url: '../test/test?testId=' + testId
    })
  }
})

2. 頁面

三掸刊、 答題頁 和 答題結(jié)束頁

不管是001還是002試題,都是共用一套頁面模板赢乓。在這個(gè)頁面要實(shí)現(xiàn)答題(含:每次進(jìn)入試卷試題都要亂序排列)忧侧、評分、查看錯(cuò)題牌芋、記錄答題數(shù)據(jù)(時(shí)間/試題id/得分)的功能蚓炬。

1. 實(shí)現(xiàn)簡單的問答頁面 (test頁面)

首先新建一個(gè)test頁面文件夾,在test.wxml文件里編寫我們的答題模板躺屁。第一步先不要考慮亂序排列和記錄答題功能肯夏,只先實(shí)現(xiàn)簡單的選擇答案和下一題、評分的功能。

test.wxml 解析

答題模板很簡單驯击,主要由題目烁兰、答案(單選/多選)、下一題(提交)徊都、退出答題組成沪斟。

test.wxml 代碼
<!--pages/test/test.wxml-->
<view class="page">
  <!--標(biāo)題-->
  <view class='page__hd'>
    <view class="page__title">
      {{index+1}}、{{questionList[index].question}}
      {{questionList[index].type==1?"【單選】":"【多選】"}}
      ({{questionList[index].scores}}分)
    </view>
  </view>
  <!--內(nèi)容-->
  <view class="page__bd">
    <radio-group class="radio-group" bindchange="radioChange" wx:if="{{questionList[index].type == 1}}">
      <label class="radio my-choosebox" wx:for="{{questionList[index].option}}" wx:for-index="key"  wx:for-item="value">
        <radio value="{{key}}" checked="{{questionList[index].checked}}"/>{{key}}暇矫、{{value}}
      </label>
    </radio-group>
    <checkbox-group bindchange="checkboxChange" wx:else>
      <label class="checkbox my-choosebox" wx:for="{{questionList[index].option}}" wx:for-index="key"  wx:for-item="value">
        <checkbox value="{{key}}" checked="{{questionList[index].checked}}"/>{{key}}币喧、{{value}}
      </label>
    </checkbox-group>
  </view>
  <!--按鈕-->
  <view class='page_ft'>
    <view class='mybutton'>
      <button bindtap='nextSubmit' wx:if="{{index == questionList.length-1}}">提交</button>
      <button bindtap='nextSubmit' wx:else>下一題</button>
      <text bindtap='outTest' class="toindex-btn">退出答題</text>
    </view>
  </view>
</view>

test.wxss 樣式
/* pages/test/test.wxss */
.page {
  padding: 20rpx;
}
.page__bd {
  padding: 20rpx;
}
.my-choosebox {
  display: block;
  margin-bottom: 20rpx;
}
.toindex-btn {
  margin-top: 20rpx;
  display:inline-block;
  line-height:2.3;
  font-size:13px;
  padding:0 1.34em;
  color:#576b95;
  text-decoration:underline;
  float: right;
}
test.js 解析

test.js
var app = getApp();
Page({
  data: {
    index: 0,  // 題目序列
    chooseValue: [], // 選擇的答案序列
    totalScore: 100, // 總分
    wrongList: [], // 錯(cuò)誤的題目集合
  },
  onLoad: function (options) {
    console.log(options);
    wx.setNavigationBarTitle({ title: options.testId }) // 動(dòng)態(tài)設(shè)置導(dǎo)航條標(biāo)題

    this.setData({
      questionList: app.globalData.questionList[options.testId],  // 拿到答題數(shù)據(jù)
      testId: options.testId // 課程ID
    })
  },
  /*
  * 單選事件
  */
  radioChange: function (e) {
    console.log('checkbox發(fā)生change事件,攜帶value值為:', e.detail.value)
    this.data.chooseValue[this.data.index] = e.detail.value;
    console.log(this.data.chooseValue);
  },
  /*
  * 多選事件
  */
  checkboxChange: function (e) {
    console.log('checkbox發(fā)生change事件袱耽,攜帶value值為:', e.detail.value)
    this.data.chooseValue[this.data.index] = e.detail.value.sort();
    console.log(this.data.chooseValue);
  },
  /*
  * 下一題/提交 按鈕
  */
  nextSubmit: function () {
    // 如果沒有選擇
    if (this.data.chooseValue[this.data.index] == undefined || this.data.chooseValue[this.data.index].length == 0) {
      wx.showToast({
        title: '請選擇至少一個(gè)答案!',
        icon: 'none',
        duration: 2000,
        success: function () {
          return;
        }
      })
      return;
    }

    // 判斷答案是否正確
    this.chooseError();

    // 判斷是不是最后一題
    if (this.data.index < this.data.questionList.length - 1) {
      // 渲染下一題
      this.setData({
        index: this.data.index + 1
      })
    } else {
      // 跳轉(zhuǎn)到結(jié)果頁

    }
  },
  /*
  * 錯(cuò)題處理
  */
  chooseError: function () {
    var trueValue = this.data.questionList[this.data.index]['true'];
    var chooseVal = this.data.chooseValue[this.data.index];
    console.log('選擇了' + chooseVal + '答案是' + trueValue);
    if (chooseVal.toString() != trueValue.toString()) {
      this.data.wrongList.push(this.data.index);
      this.setData({
        totalScore: this.data.totalScore - this.data.questionList[this.data.index]['scores']  // 扣分操作
      })
    }
  }
})

至此杀餐,一個(gè)簡單的答題、下一題的頁面就完成了朱巨。

2. 答題結(jié)束頁(results頁面)

前面我們實(shí)現(xiàn)了題目的展示和下一題的操作史翘,那到最后一題的提交按鈕應(yīng)該發(fā)生什么呢?通常是告訴用戶一個(gè)答題結(jié)果冀续。下面我們新建一個(gè)results頁面來專門展示用戶答題結(jié)果(包括得分琼讽、評價(jià)、查看錯(cuò)題按鈕和返回首頁按鈕)

test.js 跳轉(zhuǎn)傳參
// 跳轉(zhuǎn)到結(jié)果頁
let wrongList = JSON.stringify(this.data.wrongList);
let chooseValue = JSON.stringify(this.data.chooseValue);
wx.navigateTo({
    url: '../results/results?totalScore=' + this.data.totalScore + '&wrongList=' + wrongList + '&chooseValue=' + chooseValue
})

首先我們要完善test.js里的nextSubmit函數(shù)洪唐,使點(diǎn)擊提交按鈕的時(shí)候跳轉(zhuǎn)到results結(jié)果頁钻蹬。這里我們傳入了totalScore得分、wrongList錯(cuò)題集合凭需、chooseValue用戶選擇的答案集合三個(gè)數(shù)據(jù)问欠。

results.wxml

我們先來看結(jié)果頁的頁面結(jié)構(gòu)


results.wxml 代碼

<view class="page">
  <!--標(biāo)題-->
  <view class='page-head'>
    <view class="page-title">
      答題結(jié)束!您的得分為:
    </view>
    <!--分?jǐn)?shù)-->
    <view class='page-score'>
      <text class="score-num">{{totalScore}}</text>
      <text class="score-text">分</text>
    </view>
    <text class="score-remark">{{totalScore==100?remark[0]:(totalScore>=80?remark[1]:remark[2])}}</text>  <!-- 評價(jià) -->
  </view>
  <!--查詢錯(cuò)誤-->
  <view class='page-footer'>
    <view class="wrong-view" wx:if="{{wrongList.length > 0}}">
      <text>錯(cuò)誤的題數(shù):</text>
      <text wx:for="{{wrongList}}">[{{item-0+1}}]</text> 題
    </view>
    <view class="wrong-btns">
      <button type="default" bindtap="toView" hover-class="other-button-hover" class="wrong-btn" wx:if="{{wrongList.length > 0}}"> 點(diǎn)擊查看 </button>
      <button type="default" bindtap="toIndex" hover-class="other-button-hover" class="wrong-btn"> 返回首頁 </button>
    </view>
  </view>
</view>
results.js
// pages/results/results.js
var app = getApp();
Page({
  data: {
    totalScore: null, // 分?jǐn)?shù)
    wrongList: [], // 錯(cuò)誤的題數(shù)
    chooseValue: [], // 選擇的答案
    remark: ["好極了粒蜈!你很棒棒哦", "哎喲不錯(cuò)哦", "別灰心顺献,繼續(xù)努力哦!"], // 評語
  },
  onLoad: function (options) {
    console.log(options);
    wx.setNavigationBarTitle({ title: options.testId }) // 動(dòng)態(tài)設(shè)置導(dǎo)航條標(biāo)題

    let wrongList = JSON.parse(options.wrongList);
    let chooseValue = JSON.parse(options.chooseValue);
    this.setData({
      totalScore: options.totalScore,
      wrongList: wrongList,
      chooseValue: chooseValue
    })
    console.log(this.data.chooseValue);
  },
  // 查看錯(cuò)題
  toView: function () {

  },
  // 返回首頁
  toIndex: function () {
    wx.switchTab({
      url: '../home/home'
    })
  }
})
  • 解析: 我們可以看到在onLoad函數(shù)里枯怖,拿到了我們需要的數(shù)據(jù):totalScore 用戶得分注整、 wrongList 錯(cuò)題集合、 chooseValue 用戶選擇的答案度硝。接下來會(huì)自動(dòng)渲染到頁面上肿轨。
  • 數(shù)組類型的數(shù)據(jù)要經(jīng)過JSON.parse()轉(zhuǎn)換。

四蕊程、 查看錯(cuò)題彈層組件

查看錯(cuò)題彈窗(wrongModal彈窗組件)

我們看到results頁面有一個(gè)點(diǎn)擊查看的按鈕椒袍,當(dāng)點(diǎn)擊它的時(shí)候,會(huì)彈出一個(gè)層存捺,展示用戶的錯(cuò)題信息槐沼。包括錯(cuò)誤的題目,用戶選擇的答案和該題正確的答案捌治。


results 使用組件彈層

首先要在results.json文件里進(jìn)行配置

// results.json
{
  "navigationBarTitleText": "WeChatTest",
  "usingComponents": {
    "wrong-modal": "/components/wrongModal/wrongModal"
  }
}

然后在results.wxml里引入組件

<wrong-modal modalShow="{{modalShow}}" wrongList="{{wrongList}}" wrongListSort="{{wrongListSort}}" chooseValue="{{chooseValue}}" questionList="{{questionList}}" testId="{{testId}}"></wrong-modal>
wrongModal.wxml
<!--components/wrongModal/wrongModal.wxml-->
<view class="modal-page" wx:if="{{modalShow}}">
  <view class="modal-mask" bindtap="closeModal"></view>
  <!-- 內(nèi)容 -->
  <view class="modal-content">
    <view class="modal-title">
      題目: {{questionList[wrongList[index]].question}} 
      {{questionList[wrongList[index]].type==1?"【單選】":"【多選】"}}
      ({{questionList[wrongList[index]].scores}}分)
    </view>
    <view class="modal-body">
      <radio-group class="radio-group" bindchange="radioChange" wx:if="{{questionList[wrongList[index]].type == 1}}">
        <label class="radio my-choosebox" wx:for="{{questionList[wrongList[index]].option}}" wx:for-index="key"  wx:for-item="value">
          <radio disabled="{{true}}" value="{{key}}" checked="{{questionList[wrongList[index]].checked}}"/>{{key}}岗钩、{{value}}
        </label>
      </radio-group>
      <checkbox-group bindchange="checkboxChange" wx:else>
        <label class="checkbox my-choosebox" wx:for="{{questionList[wrongList[index]].option}}" wx:for-index="key"  wx:for-item="value">
          <checkbox disabled="{{true}}" value="{{key}}" checked="{{questionList[wrongList[index]].checked}}"/>{{key}}、{{value}}
        </label>
      </checkbox-group>
    </view>
    <!-- 答案解析 -->
    <view class="modal-answer">
      <text class="answer-text wrong-answer">
        您的答案為 {{chooseValue[wrongList[index]]}}
      </text>
      <text class="answer-text true-answer">
        正確答案為 {{questionList[wrongList[index]]['true']}}
      </text>
    </view>
    <!-- 操作按鈕 -->
    <view class="modal-button">
      <view wx:if="{{index == wrongList.length-1}}" class="modal-btns">
        <button bindtap='again' class="modal-btn">再來一次</button>
        <button bindtap='toIndex' class="modal-btn">返回首頁</button>
      </view>
      <button bindtap='next' wx:else class="modal-btn">下一題</button>
    </view>
  </view>
</view>
wrongModal.js
// components/wrongModal/wrongModal.js
Component({
  /**
   * 組件的屬性列表
   */
  properties: {
    // 是否顯示
    modalShow: {
      type: Boolean,
      value: false
    },
    // 題庫
    questionList: {
      type: Array,
      value: []
    },
    // 課程ID
    testId: {
      type: String,
      value: '101-1'
    },
    // 錯(cuò)題題序集合
    wrongList: {
      type: Array,
      value: []
    },
    // 選擇的答案集合
    chooseValue: {
      type: Array,
      value: []
    }
  },
  /**
   * 組件的初始數(shù)據(jù)
   */
  data: {
    index: 0 // wrongList的index
  },
  /**
   * 組件的方法列表
   */
  methods: {
    // 下一題
    next: function () {
      if (this.data.index < this.data.wrongList.length - 1) {
        // 渲染下一題
        this.setData({
          index: this.data.index + 1
        })
      }
    },
    // 關(guān)閉彈窗
    closeModal: function () {
      this.setData({
        modalShow: false
      })
    },
    // 再來一次
    again: function () {
      wx.reLaunch({
        url: '../test/test?testId=' + this.data.testId
      })
    },
    // 返回首頁
    toIndex: function () {
      wx.reLaunch({
        url: '../home/home'
      })
    }
  }
})

看代碼很容易理解肖油,主要是在Component組件的properties定義組件要接收的數(shù)據(jù)兼吓,methods里定義方法。不管是文件結(jié)構(gòu)還是事件都和test頁面很像森枪。區(qū)別主要是wrongModal頁面展示是篩選過的用戶答錯(cuò)的題视搏。

  • 解析
questionList[wrongList[index]]  // 試題[錯(cuò)題集合[當(dāng)前index]]
例如用戶第2、3題答題錯(cuò)誤(index從0開始)  錯(cuò)題集合=[2,3] 當(dāng)前index=0 下一題index+1
那么依次展示的就是questionList[2]县袱、questionList[3]題

現(xiàn)在浑娜,一個(gè)簡單的答題小程序就實(shí)現(xiàn)了。 但是現(xiàn)在每次出現(xiàn)的題都是固定的式散,假如我們001題庫里有20道題筋遭,要求每次隨機(jī)抽選10道題考核,并且這10道題亂序排列暴拄。應(yīng)該怎么做呢漓滔?只要加一個(gè)亂序的步驟就可以了。

五乖篷、 亂序抽題

1. 實(shí)現(xiàn)亂序抽題

js代碼
  onLoad: function (options) {
    // ... ...省略

    let count = this.generateArray(0, this.data.questionList.length - 1); 
    this.setData({
      shuffleIndex: this.shuffle(count).slice(0, 10) // 生成隨機(jī)題序并進(jìn)行截取
    })
    console.log(this.data.shuffleIndex); // [2,0,3,1,5,4...]
  },
  /*
  * 數(shù)組亂序/洗牌
  */
  shuffle: function (arr) {
    let i = arr.length;
    while (i) {
      let j = Math.floor(Math.random() * i--);
      [arr[j], arr[i]] = [arr[i], arr[j]];
    }
    return arr;
  },
  /**
   * 生成一個(gè)從 start 到 end 的連續(xù)數(shù)組
   */
  generateArray: function (start, end) {
    return Array.from(new Array(end + 1).keys()).slice(start)
  },
test.wxml
  • 解析:
    把頁面上所有的questionList[index] 替換成 questionList[shuffleIndex[index]],
    shuffleIndex 是一個(gè)數(shù)組响驴,里面存放亂序以后的題目下標(biāo)。用index控制依次展示亂序后的題撕蔼。

2. 完善結(jié)果頁 和 錯(cuò)題彈層組件

  • 做完以上哪些豁鲤,我們發(fā)現(xiàn):
  1. results頁面錯(cuò)誤的題序也亂序了
  2. 點(diǎn)擊查看彈出的wrongModal的錯(cuò)題和用戶答錯(cuò)的題不一致(因?yàn)閣rongModal里的數(shù)據(jù)依然是正序排列的題目下標(biāo))
  3. 用戶選擇的答案和wrongModal里展示的選擇的答案不一致。(原因同上)
  • 解決:
test頁面(test.js)

① data

data: {
    index: 0,  // 題目序列
    chooseValue: [], // 選擇的答案序列
    totalScore: 100, // 總分
    wrongList: [], // 錯(cuò)誤的題目集合-亂序
    wrongListSort: [], // 錯(cuò)誤的題目集合-正序
},

data里新增wrongListSort集合

② chooseError方法

// chooseError 錯(cuò)題處理方法更改如下
chooseError: function () {
    var trueValue = this.data.questionList[this.data.shuffleIndex[this.data.index]]['true'];
    var chooseVal = this.data.chooseValue[this.data.index];
    console.log('選擇了' + chooseVal + '答案是' + trueValue);
    if (chooseVal.toString() != trueValue.toString()) {
      this.data.wrongList.push(this.data.shuffleIndex[this.data.index]);
      this.data.wrongListSort.push(this.data.index);
      this.setData({
        totalScore: this.data.totalScore - this.data.questionList[this.data.shuffleIndex[this.data.index]]['scores']  // 扣分操作
      })
    }
  }
  • 解析:
var trueValue = this.data.questionList[this.data.shuffleIndex[this.data.index]]['true'];
// 當(dāng)前正確答案更新為 亂序排列后的當(dāng)前題的正確答案

this.data.wrongList.push(this.data.shuffleIndex[this.data.index]);
// wrongList錯(cuò)題集合里保存 亂序排列后的錯(cuò)題題序鲸沮,
如錯(cuò)誤的題為: [2,0,3] 相當(dāng)于 001題庫的[2,0,3]

this.data.wrongListSort.push(this.data.index);
// wrongListSort錯(cuò)題集合里保存 當(dāng)前題目相對于亂序排列后的題的下標(biāo) 
例如 shuffleIndex = [2,0,1,3] 用戶做錯(cuò)了第3畅形、4題, wrongListSort保存為[2,3]

this.setData({
    totalScore: this.data.totalScore - this.data.questionList[this.data.shuffleIndex[this.data.index]]['scores']  // 扣分操作
})
// 扣分操作诉探,邏輯同上日熬,扣的是亂序后對應(yīng)的題目分值

③ nextSubmit 方法

// 判斷是不是最后一題
if (this.data.index < this.data.questionList.length - 1) {
    // ...
} else {
  // 跳轉(zhuǎn)到結(jié)果頁
  let wrongList = JSON.stringify(this.data.wrongList);
  let wrongListSort = JSON.stringify(this.data.wrongListSort);
  let chooseValue = JSON.stringify(this.data.chooseValue);
  wx.navigateTo({
    url: '../results/results?totalScore=' + this.data.totalScore + '&wrongList=' + wrongList + '&chooseValue=' + chooseValue + '&wrongListSort=' + wrongListSort + '&testId=' + this.data.testId
  })
}

把wrongListSort傳遞給results頁面(注:這里的wrongList也已經(jīng)更新為亂序后的題目集合)

results頁面

① results.js

// results.js
data: {
    wrongList: [], // 錯(cuò)誤的題數(shù)-亂序
    wrongListSort: [],  // 錯(cuò)誤的題數(shù)-正序
},
onLoad: function (options) {
    // ... 省略

    let wrongList = JSON.parse(options.wrongList);
    let wrongListSort = JSON.parse(options.wrongListSort);

    this.setData({
      wrongList: wrongList,
      wrongListSort: wrongListSort,
    })
},

data里定義wrongListSort,onLoad生命周期里接收并且賦值肾胯。

② results.wxml

// results.wxml
<view class="wrong-view" wx:if="{{wrongList.length > 0}}">
    <text>錯(cuò)誤的題數(shù):</text>
    <text wx:for="{{wrongListSort}}">[{{item-0+1}}]</text> 題
</view>

<wrong-modal modalShow="{{modalShow}}" wrongList="{{wrongList}}" wrongListSort="{{wrongListSort}}" chooseValue="{{chooseValue}}" questionList="{{questionList}}" testId="{{testId}}"></wrong-modal>
  • 解析:
    錯(cuò)誤的題數(shù): 如果展示wrongList則是[2],[0],[3]的相對于題庫的亂序效果竖席,wrongListSort 則顯示相對于當(dāng)次測試的錯(cuò)題index。

<wrong-modal>組件綁定wrongListSort數(shù)據(jù)敬肚。因?yàn)椋?br> wrongListSort還有另一個(gè)需要用到的場景毕荐,即wrongModal錯(cuò)題彈層,展示“你選擇的答案是XX”艳馒。在test.js里憎亚,我們保存用戶本次考試的選項(xiàng)集合是根據(jù)當(dāng)前題目的下標(biāo)员寇,

// test.js
this.data.chooseValue[this.data.index] = e.detail.value;

例如一共有三道題,this.data.chooseValue = ["B","C",["A","D"]]對應(yīng)三道題的用戶選項(xiàng)第美,
假如用戶答錯(cuò)第二蝶锋、三題,wrongListSort里存放的就是[1,2]的錯(cuò)題下標(biāo)什往,通過index切換可以依次得到當(dāng)前錯(cuò)題的用戶選項(xiàng)扳缕。

// wrongModal.wxml
{{chooseValue[wrongListSort[index]]}}
wrongModal組件

① wrongModal.js

// wrongModal.js
  properties: {
    // ... 省略
    // 錯(cuò)題題數(shù)-亂序
    wrongList: {
      type: Array,
      value: []
    },
    // 錯(cuò)題題數(shù)-正序
    wrongListSort: {
      type: Array,
      value: []
    }
  },

properties新定義要接收的 wrongListSort 數(shù)據(jù)

① wrongModal.wxml

// wrongModal.wxml
<!-- 答案解析 -->
<view class="modal-answer">
  <text class="answer-text wrong-answer">
    您的答案為 {{chooseValue[wrongListSort[index]]}}
  </text>
  <text class="answer-text true-answer">
    正確答案為 {{questionList[wrongList[index]]['true']}}
  </text>
</view>

【您的答案為】 表達(dá)式更新。

五别威、 緩存用戶的答題數(shù)據(jù)

首先我們需要一個(gè)Logs頁面來展示用戶的答題數(shù)據(jù)躯舔。在新建小程序項(xiàng)目時(shí)已經(jīng)生成了一個(gè)Logs頁面,我們就在上面改改就好省古。

1. 設(shè)置緩存

因?yàn)槭羌兦岸说男〕绦蛑嘧晕覀冇镁彺鎭肀4娲痤}記錄。 在test.js里設(shè)置豺妓。


// test.js

  // 設(shè)置緩存
  var logs = wx.getStorageSync('logs') || []
  let logsList = { "date": Date.now(), "testId": this.data.testId, "score": this.data.totalScore }
  logs.unshift(logsList);
  wx.setStorageSync('logs', logs);

每次答題結(jié)束都拿到當(dāng)前的logs緩存數(shù)據(jù)飒赃,在logList手動(dòng)定義數(shù)據(jù)格式(當(dāng)前時(shí)間戳/試題id/得分),追加到拿到的logs數(shù)據(jù)里科侈,最后調(diào)用wx.setStorageSync()接口保存logs數(shù)據(jù)载佳。

2. 拿到緩存

logs.js

//logs.js
const util = require('../../utils/util.js')

Page({
  data: {
    logs: [],
  },
  onShow: function () {
    this.setData({
      logs: this.formatLogs()
    })
  },
  // 拿到緩存并格式化日期數(shù)據(jù)
  formatLogs: function () {
    let newList = [];
    (wx.getStorageSync('logs') || []).forEach(log => {
      if (log.date) {
        log['date'] = util.formatTime(new Date(log.date));
        newList.push(log);
      }
    })
    return newList;
  }
})

因?yàn)閿?shù)據(jù)的時(shí)間是個(gè)時(shí)間戳,所以我們導(dǎo)入util.js文件臀栈,使用里面的formatTime方法來轉(zhuǎn)換時(shí)間格式蔫慧。
在data里我們定義了logs空數(shù)組,在formatLogs函數(shù)里進(jìn)行wx.getStorageSync('logs')拿到緩存并遍歷-轉(zhuǎn)換時(shí)間格式-添加到新的空數(shù)組权薯,最后返回新數(shù)組的操作姑躲。在OnShow生命周期里,我們調(diào)用formatLogs方法盟蚣,給logs賦值黍析。

3. 數(shù)據(jù)渲染

logs.wxml
<!--logs.wxml-->
<view class="page">
  <view class="table" wx:if="{{logs.length>0}}">
    <view class="tr bg-w">
      <view class="th first">時(shí)間</view>
      <view class="th">試題</view>
      <view class="th ">得分</view>
    </view>
    <block wx:for="{{logs}}" wx:for-item="item">
      <view class="tr">
        <view class="td first">{{item.date}}</view>
        <view class="td">{{item.testId}}</view>
        <view class="td">{{item.score}}</view>
      </view>
    </block>
  </view>
  <view class="no-record" wx:else>
    <image src="/image/wechat.png" class="no-image"></image>
    <text class="no-text">沒有數(shù)據(jù)哦~</text>
  </view>
</view>

自己寫一個(gè)table結(jié)構(gòu),遍歷logs緩存數(shù)據(jù)屎开,展示 答題時(shí)間/試題id/得分 等數(shù)據(jù)阐枣。 這里我們還進(jìn)行了判斷,如果沒有數(shù)據(jù)奄抽,展示沒有數(shù)據(jù)的提示蔼两。

logs.wxss
.table {
 border: 0px solid darkgray;
 font-size: 12px;
}
.tr {
 display: flex;
 width: 100%;
 justify-content: center;
 height: 2rem;
 align-items: center;
}
.td {
  width:40%;
  justify-content: center;
  text-align: center;
}
.bg-w{
 background: snow;
}
.th {
 width: 40%;
 justify-content: center;
 background: #3366FF;
 color: #fff;
 display: flex;
 height: 2rem;
 align-items: center;
}
.first {
  flex:1 0 auto;
}
.no-record {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.no-image {
  width: 200rpx;
  height: 200rpx;
  margin-top: 200rpx;
  margin-bottom: 40rpx;
}
.no-text {
  font-size: 16px;
  color: #ccc;
  display: block;
}

4. tabBar頁面

這里我們已經(jīng)完成了logs頁面,但是它的入口在哪里呢逞度?不要急额划,我們現(xiàn)在把home頁改改,改成tabBar頁面档泽。

app.json
  "tabBar": {
    "color": "#666666",
    "selectedColor": "#3cc51f",
    "borderStyle": "black",
    "backgroundColor": "#ffffff",
    "list": [
      {
        "pagePath": "pages/home/home",
        "iconPath": "image/icon_component.png",
        "selectedIconPath": "image/icon_component_HL.png",
        "text": "答題"
      },
      {
        "pagePath": "pages/logs/logs",
        "iconPath": "image/icon_API.png",
        "selectedIconPath": "image/icon_API_HL.png",
        "text": "記錄"
      }
    ]
  }

首先在app.json里配置tabBar參數(shù)俊戳。圖片放在和pages同級的image文件夾中揖赴。

在index.js中,使用 wx.switchTab 跳轉(zhuǎn)到tabBar頁抑胎。

// index.js
bindViewTap: function() {
    wx.switchTab({
      url: '../home/home'
    })
}
效果
GitHub源碼地址

答題類微信小程序完整源碼

end.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末燥滑,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子圆恤,更是在濱河造成了極大的恐慌突倍,老刑警劉巖腔稀,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盆昙,死亡現(xiàn)場離奇詭異区匣,居然都是意外死亡骡楼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門锈颗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诵闭,“玉大人炼团,你說我怎么就攤上這事∈枘颍” “怎么了瘟芝?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長褥琐。 經(jīng)常有香客問我锌俱,道長,這世上最難降的妖魔是什么敌呈? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任贸宏,我火速辦了婚禮,結(jié)果婚禮上磕洪,老公的妹妹穿的比我還像新娘吭练。我一直安慰自己,他們只是感情好析显,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布鲫咽。 她就那樣靜靜地躺著,像睡著了一般谷异。 火紅的嫁衣襯著肌膚如雪浑侥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天晰绎,我揣著相機(jī)與錄音寓落,去河邊找鬼。 笑死荞下,一個(gè)胖子當(dāng)著我的面吹牛伶选,可吹牛的內(nèi)容都是我干的史飞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼仰税,長吁一口氣:“原來是場噩夢啊……” “哼构资!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起陨簇,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤吐绵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后河绽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體己单,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年耙饰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纹笼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡苟跪,死狀恐怖廷痘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情件已,我是刑警寧澤笋额,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站篷扩,受9級特大地震影響兄猩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瞻惋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一厦滤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧歼狼,春花似錦掏导、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至梅屉,卻和暖如春值纱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背坯汤。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工虐唠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人惰聂。 一個(gè)月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓疆偿,卻偏偏與公主長得像咱筛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子杆故,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 原文:http://gold.xitu.io/entry/57e34d6bd2030900691e9ad7/pro...
    AiPuff閱讀 2,493評論 0 3
  • 1.小程序起步 (1)點(diǎn)擊https://mp.weixin.qq.com/wxopen/waregister?a...
    GXW_Lyon閱讀 3,345評論 0 0
  • 都說在愛情里主動(dòng)的必須是男人,不管你有多么在乎一個(gè)男人撤蟆,如果他不主動(dòng)奕塑,寧愿錯(cuò)過。我也堅(jiān)信這條真理枫疆。 可是明明在乎彼...
    戴簡一閱讀 293評論 0 0
  • 猴年如期而至爵川,祝福接著送上敷鸦∠⑿ǎ快樂日漸增長,幸福情深意長扒披。健康一如既往值依,平安地久天長。新年更新萬象碟案,精彩天天點(diǎn)亮愿险。祝...
    心草閱讀 261評論 0 0
  • 不得不說辆亏,寫作是有助于理清思路的。 就在我連發(fā)了兩篇跪舔簡書+批判微信朋友圈的文章以后鳖目,我發(fā)現(xiàn)我要退出什么跟工具怎...
    無限爸爸閱讀 295評論 5 4