如何使用Math.random()随机化问卷题目且不打乱选项顺序?
解决随机展示题目且保持选项顺序的问题
我看了你的代码,核心问题在于你写的Random函数没有和现有的答题流程结合起来,而且函数里还存在变量未初始化、引用错误的问题(比如你用了questions变量,但实际你的题目数组是myQuestions,questionTracker也没提前声明)。
下面是修改后的完整代码,我调整了逻辑:先对题目数组进行公平打乱,然后基于打乱后的数组构建答题内容,这样既实现了题目随机展示,又完全保留每个题目的选项顺序:
(function() { const myQuestions = [ { question: "Esimerkki kysymys1", answers: { a: "Oikein", b: "Vääärin" }, correctAnswer: "a" }, { question: "Esimerkki kysymys2", answers: { a: "Oikein", b: "Vääärin" }, correctAnswer: "b" }, { question: "Esimerkki kysymys3", answers: { a: "Oikein", b: "Vääärin" }, correctAnswer: "a" } ]; // Fisher-Yates洗牌算法:公平打乱题目数组,不修改原数组 function shuffleQuestions(questions) { const shuffled = [...questions]; for (let i = shuffled.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; } return shuffled; } function buildQuiz() { // 先打乱题目数组 const shuffledQuestions = shuffleQuestions(myQuestions); const output = []; // 遍历打乱后的题目数组构建内容 shuffledQuestions.forEach((currentQuestion, questionNumber) => { const answers = []; for (letter in currentQuestion.answers) { answers.push( `<label> <input type="radio" name="question${questionNumber}" value="${letter}"> ${letter} : ${currentQuestion.answers[letter]} </label>` ); } output.push( `<div class="slide"> <div class="question"> ${currentQuestion.question} </div> <div class="answers"> ${answers.join("")} </div> </div>` ); }); quizContainer.innerHTML = output.join(""); // 返回打乱后的题目,方便showResults函数使用 return shuffledQuestions; } function showResults(shuffledQuestions) { const answerContainers = quizContainer.querySelectorAll(".answers"); let numCorrect = 0; // 基于打乱后的题目数组验证答案 shuffledQuestions.forEach((currentQuestion, questionNumber) => { const answerContainer = answerContainers[questionNumber]; const selector = `input[name=question${questionNumber}]:checked`; const userAnswer = (answerContainer.querySelector(selector) || {}).value; if (userAnswer === currentQuestion.correctAnswer) { numCorrect++; answerContainers[questionNumber].style.color = "lightgreen"; } else { answerContainers[questionNumber].style.color = "red"; } }); resultsContainer.innerHTML = `${numCorrect} Oikein ${shuffledQuestions.length}`; } 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"; } } function showNextSlide() { showSlide(currentSlide + 1); } function showPreviousSlide() { showSlide(currentSlide - 1); } const quizContainer = document.getElementById("quiz"); const resultsContainer = document.getElementById("results"); const submitButton = document.getElementById("submit"); // 构建quiz并获取打乱后的题目数组 const shuffledQuestions = buildQuiz(); const previousButton = document.getElementById("previous"); const nextButton = document.getElementById("next"); const slides = document.querySelectorAll(".slide"); let currentSlide = 0; showSlide(0); // 提交时传入打乱后的题目数组验证答案 submitButton.addEventListener("click", () => showResults(shuffledQuestions)); previousButton.addEventListener("click", showPreviousSlide); nextButton.addEventListener("click", showNextSlide); })();
关键修改说明:
- 新增了
shuffleQuestions函数,使用Fisher-Yates洗牌算法对题目数组进行打乱,这个算法能保证每个元素被随机到任意位置的概率相等,是业内公认的公平洗牌方法,而且我们是基于原数组的副本进行打乱,不会修改原始的题目数据 - 修改了
buildQuiz函数,先调用洗牌函数得到打乱后的题目数组,再基于这个数组生成答题HTML,同时返回打乱后的数组给showResults使用 - 调整了
showResults函数,接收打乱后的题目数组作为参数,这样验证答案时能和用户看到的随机题目一一对应 - 移除了原代码中未生效的
Random函数,把随机逻辑整合到了正常的答题流程里
内容的提问来源于stack exchange,提问作者Zami Coskula
相关产品推荐
相关产品推荐

