製作 JavaScript 測驗表 demo

yuyurenjie發表於2017-05-29

本文通過分段敘述JavaScript程式碼實現測驗demo,此demo功能如下:

  • 可自定義問題及答案
  • 分頁顯示問題
  • 顯示答對題目數目
  • 對於正確和錯誤答案就行區分
  • 倒數計時功能

測驗的基本結構

首先,羅列測驗問題和答案在JavaScript程式碼中,然後指令碼就會自動產生測驗。因此就不需要許多重複的程式碼,可以很容易增加或刪除問題。

HTML結構如下:

  • <div>放置問題
  • <button>提交測驗答案
  • <div>顯示結果
<div id="quiz"></div>
<button id="submit">Submit Quiz</button>
<div id="results"></div>複製程式碼

然後通過DOM操作引用這些元素。

const quizContainer = document.getElementById('quiz');
const resultsContainer = document.getElementById('results');
const submitButton = document.getElementById('submit');複製程式碼

接著,我們需要方法建立測驗表,顯示結果。

function buildQuiz(){}

function showResults(){}

// 顯示測驗表
buildQuiz();

// 監聽提交事件,執行showResults方法
submitButton.addEventListener('click', showResults);複製程式碼

顯示測驗問題

我們需要將問題顯示出來,所以採用迭代方法。就需要用陣列來裝載所有問題,而且用陣列結構迭代更容易。

const myQuestions = [
  {
    question: "Who is the strongest?",
    answers: {
      a: "Superman",
      b: "The Terminator",
      c: "Waluigi, obviously"
    },
    correctAnswer: "c"
  },
  {
    question: "What is the best site ever created?",
    answers: {
      a: "SitePoint",
      b: "Simple Steps Code",
      c: "Trick question; they're both the best"
    },
    correctAnswer: "c"
  },
  {
    question: "Where is Waldo really?",
    answers: {
      a: "Antarctica",
      b: "Exploring the Pacific Ocean",
      c: "Sitting in a tree",
      d: "Minding his own business, so stop asking"
    },
    correctAnswer: "d"
  }
];複製程式碼

現在我們開始羅列問題,並將其顯示到頁面中。

function buildQuiz(){
  // output陣列存放輸出結果
  const output = [];

  // 問題迭代
  myQuestions.forEach(
    (currentQuestion, questionNumber) => {

      // answers陣列存放問題的答案
      const answers = [];

      for(letter in currentQuestion.answers){

        // 新增單選按鈕
        answers.push(
          `<label>
            <input type="radio" name="question${questionNumber}" value="${letter}">
            ${letter} :
            ${currentQuestion.answers[letter]}
          </label>`
        );
      }

      // 將問題和答案放入output陣列中
      output.push(
        `<div class="question"> ${currentQuestion.question} </div>
        <div class="answers"> ${answers.join('')} </div>`
      );
    }
  );

  // 將output陣列轉換為string型別,輸出到網頁頁面
  quizContainer.innerHTML = output.join('');
}複製程式碼

顯示測驗結果

使用showResults迭代問題答案,檢查他們,並顯示結果

function showResults(){

  // 獲取所有answers類的元素
  const answerContainers = quizContainer.querySelectorAll('.answers');

  //記錄正確個數
  let numCorrect = 0;

  // 迭代問題
  myQuestions.forEach( (currentQuestion, questionNumber) => {

    //獲取所選的答案
    const answerContainer = answerContainers[questionNumber];
    const selector = 'input[name=question'+questionNumber+']:checked';
    const userAnswer = (answerContainer.querySelector(selector) || {}).value;

    //如果回答正確
    if(userAnswer===currentQuestion.correctAnswer){
      // 正確個數+1
      numCorrect++;

      //將正確答案變成綠色
      answerContainers[questionNumber].style.color = 'lightgreen';
    }
    //如果答案錯誤或者是沒答
    else{
      // 顏色變成紅色
      answerContainers[questionNumber].style.color = 'red';
    }
  });

  // 顯示答對的題目數目
  resultsContainer.innerHTML = numCorrect + ' out of ' + myQuestions.length;
}複製程式碼

處理沒答完情況

如果有題沒答,使用.value就會造成異常,因為無法獲取不存在的的.value。所以為了解決這個就需要使用或操作||

  • 獲取選擇元素的引用,如果不存在則使用空物件。
  • 獲取其值

所以,就會獲得使用者答案或undefined

最後,可以使用IIFE包裝起來,這樣就可以立即被呼叫。這樣。變數也不會暴露在全域性範圍內,而且也不會影響別的函式塊。

(function(){
  // put the rest of your code here
})();複製程式碼

增加頁碼

想讓一頁只顯示一個問題。所以需要:

  • 顯示和隱藏問題方式
  • 操作測驗表的按鈕

所以需要升級HTML結構如下:

<div class="quiz-container">
  <div id="quiz"></div>
</div>
<button id="previous">Previous Question</button>
<button id="next">Next Question</button>
<button id="submit">Submit Quiz</button>
<div id="results"></div>複製程式碼

buildQuiz函式中,增加一個slide類的div元素來放置問題和答案。

output.push(
  `<div class="slide">
    <div class="question"> ${currentQuestion.question} </div>
    <div class="answers"> ${answers.join("")} </div>
  </div>`
);複製程式碼

然後,開始放入CSS樣式,通過z-indexopacity動畫屬性來顯示或隱藏。

.slide{
  position: absolute;
  left: 0px;
  top: 0px;
  width: 100%;
  z-index: 1;
  opacity: 0;
  transition: opacity 0.5s;
}
.active-slide{
  opacity: 1;
  z-index: 2;
}
.quiz-container{
  position: relative;
  height: 200px;
  margin-top: 40px;
}複製程式碼

然後,增加JavaScript邏輯

首先需要變數來指向按鈕和現在所在頁面。

const previousButton = document.getElementById("previous");
const nextButton = document.getElementById("next");
const slides = document.querySelectorAll(".slide");
let currentSlide = 0;複製程式碼

這是顯示頁面的函式:

function showSlide(n) {
  //移出類,達到隱藏功能
  slides[currentSlide].classList.remove('active-slide');
  //增加類,達到顯示功能
  slides[n].classList.add('active-slide');
  //更新現在頁面頁碼
  currentSlide = n;
  //如果處於第一頁,則沒有前一頁按鈕
  if(currentSlide===0){
    previousButton.style.display = 'none';
  }
  else{
    previousButton.style.display = 'inline-block';
  }
  //如果最後一頁,則沒有後一頁按鈕
  if(currentSlide===slides.length-1){
    nextButton.style.display = 'none';
    submitButton.style.display = 'inline-block';
  }
  else{
    nextButton.style.display = 'inline-block';
    submitButton.style.display = 'none';
  }
}
showSlide(0);複製程式碼

然後,編寫函式來實現按鈕功能

function showNextSlide() {
  showSlide(currentSlide + 1);
}

function showPreviousSlide() {
  showSlide(currentSlide - 1);
}

previousButton.addEventListener("click", showPreviousSlide);
nextButton.addEventListener("click", showNextSlide);複製程式碼

效果如下:

增加計時功能

一般測驗都需要有時間限制。所以首先先更新HTML結構:

<div id="timer"></div>複製程式碼

放置在標題下面,題目上方

大致需要以下兩個函式,一個是將時間分割便於後來顯示,一個是初始化時鐘。

//初始化時鐘
        function initializeClock(id, endtime) {
          var clock = document.getElementById(id);


          function updateClock() {
            var t = getTimeRemaining(endtime);
            //顯示剩餘時間     
            clock.innerHTML = "剩餘時間:"+('0' + t.hours).slice(-2)+":"+('0' + t.minutes).slice(-2)+':'+('0' + t.seconds).slice(-2)

            //時間到了,自動交卷
            if (t.total <= 0) {
              showResults();
              clearInterval(timeinterval);
            }
          }

          updateClock();
          // 每秒自動更新
          var timeinterval = setInterval(updateClock, 1000);
        }複製程式碼

然後通過下面呼叫:

//設定計時1分鐘
    var deadline = new Date(Date.parse(new Date())+1*60*1000);
        initializeClock('timer', deadline);複製程式碼

但是這樣設定時間還需要計算成毫秒,所以需要另一個函式,只需要輸入計時時長,就直接就能換算成毫秒。

// 設定截止時間
        function setDeadline(hours,minutes,seconds){
          var deadline = hours*60*60*1000+minutes*60*1000+seconds*1000
          return new Date(Date.parse(new Date())+deadline);
        }複製程式碼

最終效果如下:

參考資料:

How to Make a Simple JavaScript Quiz
Build a Countdown Timer in Just 18 Lines of JavaScript


喜歡此文的同學,可以關注我的知乎專欄前端亂燉大雜燴

相關文章