本文通過分段敘述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-index
和opacity
動畫屬性來顯示或隱藏。
.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
喜歡此文的同學,可以關注我的知乎專欄前端亂燉大雜燴