То, что вы хотите, требует некоторого планирования, я предлагаю вам разбить его на компоненты / скрипты, чтобы вы могли легко вносить изменения в ваш код.
Я написал простую демонстрацию, чтобы проиллюстрировать мою точку зрения.
var questions = [
{
question: "1. question 1 here",
answers: [
"1a here",
"1b here",
"1c here",
"1d here"
],
correctanswer: "1b here"
},
{
question: "2. question 2 here",
answers: [
"2a here",
"2b here",
"2c here",
"2d here"
],
correctanswer: "2a here"
},
{
question: "3. question 3 here",
answers: [
"3a here",
"3b here",
"3c here",
"3d here"
],
correctanswer: "3d here"
},
];
function Timer(maxMinutes) {
var root = null;
var display = null;
var time = {
minutes: maxMinutes,
seconds: 0
};
var UPDATE_RATE = 1000;
var jobId = null;
var timeoutCallback = null;
function formatTime() {
var min = time.minutes;
var sec = time.seconds;
if (sec < 10) {
sec = '0' + sec;
}
return min + ':' + sec;
}
function init() {
root = document.createElement('div');
root.classList.add('quiz__timer');
display = document.createElement('span');
display.classList.add('quiz__timer__display');
display.innerText = formatTime();
root.appendChild(display)
}
function update() {
time.seconds = time.seconds - 1;
if (time.seconds < 0) {
time.minutes = time.minutes - 1;
time.seconds = 59;
}
display.innerText = formatTime();
if (time.minutes === 0 && time.seconds === 0) {
stop();
timeoutCallback();
}
}
function mount(node) {
node.appendChild(root);
}
function onTimeout(callback) {
timeoutCallback = callback;
}
function unmount() {
stop();
root.remove();
}
function start() {
jobId = window.setInterval(update, UPDATE_RATE);
}
function stop() {
if (jobId !== null) {
window.clearInterval(jobId);
jobId = null;
}
}
function getCurrentTime() {
return display.innerText;
}
init();
return {
mount: mount,
unmount: unmount,
start: start,
stop: stop,
onTimeout: onTimeout,
getCurrentTime: getCurrentTime
}
}
function Question(data) {
var root = null;
var options = null;
var validator = null;
function init() {
root = document.createElement('div');
options = document.createElement('ul');
var question = document.createElement('p');
question.innerText = data.question;
data.answers.forEach((opt) => {
var option = document.createElement('li');
option.dataset.value = opt;
option.innerText = opt;
options.appendChild(option);
});
root.classList.add('quiz__question');
options.classList.add('quiz__question__options');
question.classList.add('quiz__question__title');
root.appendChild(question);
root.appendChild(options);
}
function createValidator(callback) {
return function (ev) {
var answered = ev.target.dataset.value === data.correctanswer;
if (answered) {
ev.target.classList.add('correct');
} else {
ev.target.classList.add('incorrect');
}
options.classList.add('readonly');
callback({
question: data.question,
correct: answered
});
}
}
function onAnswer(callback) {
validator = createValidator(callback);
options.addEventListener('click', validator);
}
function mount(node) {
node.appendChild(root);
}
function unmount() {
options.removeEventListener('click', validator);
root.remove();
}
init();
return {
mount: mount,
unmount: unmount,
onAnswer: onAnswer
}
}
function Quiz(data, mountingNode, onFinish, nextQuestionRate) {
nextQuestionRate = nextQuestionRate || 2500;
var started = false;
var index = 0;
var currentQuestion = null;
var result = {
remainingTime: '',
answers: []
};
var timer = Timer(5);
timer.onTimeout(notifyResult);
function render() {
timer.mount(mountingNode);
}
function notifyResult() {
result.remainingTime = timer.getCurrentTime();
onFinish(result)
}
function renderQuestionByIndex(currentIndex) {
currentQuestion = Question(data[currentIndex]);
currentQuestion.mount(mountingNode);
currentQuestion.onAnswer(nextQuestion);
}
function nextQuestion(answer) {
result.answers.push(answer);
index += 1;
// queue next question
if (index < data.length) {
setTimeout(function () {
currentQuestion.unmount();
renderQuestionByIndex(index);
}, 2500);
} else {
notifyResult();
timer.stop();
}
}
function start() {
timer.start();
renderQuestionByIndex(index);
}
render();
return {
start: start
}
}
var quiz = Quiz(
questions,
document.querySelector('.quiz'),
function(result) {
console.log(result);
}
);
var start = document.querySelector('.quiz__start-button');
start.addEventListener('click', function(){
quiz.start();
start.disabled = true;
});
.quiz__timer {
position: absolute;
top: 0;
right: 0;
}
.quiz {
position: relative;
min-height: 200px;
}
.quiz__question__title {
margin: 0;
font-weight: 600;
margin-bottom: 10px;
}
.quiz__question__options {
list-style: none;
margin: 0;
padding: 0;
}
.readonly {
pointer-events: none;
}
.quiz__question__options li {
cursor: pointer;
padding: 10px;
}
.quiz__question__options li.correct {
background-color: #9ae6b4;
}
.quiz__question__options li.incorrect {
background-color: #feb2b2;
}
.quiz__question__options li:hover {
background: #e2e8f0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div class="quiz">
</div>
<button class="quiz__start-button">start</button>
</body>
</html>
, как показано выше, вы найдете 3 компонента
- Таймер обновляет время и уведомляет, когда у пользователя закончилось время .
- Вопрос проверяет ответ пользователя и уведомляет о его получении.
- Тест вычисляет ответы на вопрос, изменяет текущий вопрос и уведомляет о результате.