javascript - JavaScript 分页中的测验
问题描述
我正在 JS 中创建一个测验,问题一次只需要显示一个。当我选择一个答案选项时,我会收到“正确”或“错误”的通知,然后它会自动转到下一个问题。
var questions = [
{
question: "1. question 1 here",
answers: [
"1a 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 startQuiz() {
var output =[];
var answers;
for (var i=0; i < questions.length; i++) {
answers =[];
for(letter in questions[i].answers) {
answers.push(
'<label>'
+ '<input type="radio" name="question' +i+'"value="'+letter+'">'
+ letter + ': ' + questions[i].answers[letter] +
'</label'
// var userAns = document.getElementById("quiz")
// userAns.innerHTML = questions[i].question + "<br>" + questions[i].answers;
);
}
output.push(
'<div class="question">' + questions[i].question + '</div>'+
'div class="answers">' + answers.join('') + '</div>'
);
// //if right or wrong
// if (userAns === questions.correctanswer) {
// var grade = document.createElement("p");
// grade.textContent("Correct!");
// grade.className("grade");
// grade.setAttribute("grade-id");
// } else {
// grade.textContent("Wrong!");
// timerRef - sec *10;
// }
}
quizContainer.innerHTML = output.join('');
}
startButton.addEventListener('click', startTimer);
startButton.addEventListener('click', startQuiz);
我注释掉了一些行,因为我不确定如何让它们工作。我尝试制作答案选择单选按钮 - 只有在选择“开始”时才会显示问题。
解决方案
你想要什么需要一些计划,我建议你把它分解成组件/脚本,这样你就可以轻松地将更改应用到你的代码中。
我写了一个简单的演示来说明我的观点。
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 个组件
- 计时器更新时间并在用户时间用完时通知。
- 问题验证用户回答并在回答时通知。
- 测验计算问题答案,更改当前问题并通知结果。
推荐阅读
- reactjs - opentok 在悬停的顶栏中反应 OTSubscriber 自定义元素插入
- docker - 如何忽略docker使用的opengrok中的文件和目录?
- react-native - 如何在 react native 中创建和使用多个 Tab Navigator?
- c++ - 从 std::integer_sequence 调用带有模板参数的模板
- ionic-framework - SFSafariViewController 附加用户代理
- javascript - 反应更新上下文导致未捕获错误:超出最大更新深度错误
- python - Python脚本,将索引项替换为索引项
- javascript - 在画布上展开数组
- typescript - 如何仅在执行 QuickFix 操作时触发代码?
- python - Python:用'.format'格式化的字符串可以乘以'*'吗?