You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript Trivia游戏点击正确答案按钮却显示错误结果的问题

问题描述

我用原生JS和Bootstrap开发答题游戏,从API获取题目,通过生成不重复随机数组打乱答案按钮的显示顺序。添加nextQuestion函数实现题目切换后,点击正确答案按钮时不会显示“Correct!”,反而随机某个按钮会显示“Incorrect”。之前通过刷新页面生成新题目时没有这个问题。试过将randomArray设为全局变量、在nextQuestion里重置它,也打印过数组确认变化,发现大多时候上一题正确答案的位置会显示错误提示。

问题根源

  1. 事件监听器重复绑定:每次调用displayQuestion都会给按钮添加新的点击事件,同一个按钮会被绑定多个不同的处理函数。点击按钮时会执行所有绑定的函数,而此时randomArray已经被新题的数据覆盖,导致用新数组的位置去定位按钮,错误提示出现在不正确的位置。
  2. 全局变量被覆盖:randomArray是全局变量,新题加载时会被重新赋值,但之前的点击处理函数仍在引用这个变量,导致处理逻辑使用的是新题的位置数组,而非当前点击题目对应的数组。

修复方案

核心改进思路

  • 页面加载时一次性给所有按钮绑定通用点击处理函数,避免重复绑定
  • 保存当前题目的正确答案按钮ID,不再依赖易被覆盖的全局数组

修改后的完整代码

Main.js

const api_url = 'https://opentdb.com/api.php?amount=1&category=9&type=multiple&encode=url3986';
let score = 0;
let buttonClicked = false;
const delay = 2000;
let currentCorrectButtonId = ''; // 保存当前正确答案的按钮ID

// 页面初始化时绑定所有按钮的点击事件
document.getElementById('answer1').addEventListener('click', handleAnswerClick);
document.getElementById('answer2').addEventListener('click', handleAnswerClick);
document.getElementById('answer3').addEventListener('click', handleAnswerClick);
document.getElementById('answer4').addEventListener('click', handleAnswerClick);

async function getQuestion() {
    try {
        const response = await fetch(api_url);
        const data = await response.json();
        const { results } = data;
        displayQuestion(results);
    } catch (error) {
        console.log(error);
    }
}

function displayQuestion(results) {
    const question = decodeURIComponent(results[0].question);
    const correctAnswer = decodeURIComponent(results[0].correct_answer);
    const incorrectAnswers = results[0].incorrect_answers.map(ans => decodeURIComponent(ans));
    
    // 合并答案并打乱顺序
    const allAnswers = [correctAnswer, ...incorrectAnswers];
    const buttonIds = ['answer1', 'answer2', 'answer3', 'answer4'];
    shuffleArray(buttonIds);

    // 渲染题目
    document.getElementById('question').textContent = question;
    // 给按钮赋值并记录正确答案位置
    buttonIds.forEach((id, index) => {
        const button = document.getElementById(id);
        button.textContent = allAnswers[index];
        if (allAnswers[index] === correctAnswer) {
            currentCorrectButtonId = id;
        }
        // 重置按钮样式
        button.className = 'btn btn-primary btn-sm';
    });
}

// 统一处理所有按钮点击
function handleAnswerClick(e) {
    if (buttonClicked) return;
    buttonClicked = true;
    const clickedButton = e.target;

    if (clickedButton.id === currentCorrectButtonId) {
        // 正确答案逻辑
        clickedButton.innerHTML = "Correct!";
        clickedButton.className = 'btn btn-success btn-sm';
        score++;
        updateScore();
    } else {
        // 错误答案逻辑,同时高亮正确答案
        clickedButton.innerHTML = "Incorrect!";
        clickedButton.className = 'btn btn-danger btn-sm';
        const correctBtn = document.getElementById(currentCorrectButtonId);
        correctBtn.innerHTML = "Correct!";
        correctBtn.className = 'btn btn-success btn-sm';
    }

    setTimeout(() => {
        nextQuestion();
        buttonClicked = false;
    }, delay);
}

function updateScore() {
    const scoreElement = document.getElementById('score');
    scoreElement.textContent = `Score: ${score}`;
}

function nextQuestion() {
    document.getElementById('question').textContent = '';
    // 重置所有按钮状态
    ['answer1', 'answer2', 'answer3', 'answer4'].forEach(id => {
        const button = document.getElementById(id);
        button.textContent = '';
        button.className = 'btn btn-primary btn-sm';
    });
    getQuestion();
}

// Fisher-Yates标准洗牌算法
function shuffleArray(array) {
    for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
}

getQuestion();

game.html(无需修改)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Trivia Game</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
    <link href="/css/style.css" rel="stylesheet">
</head>
<body>
    <div id="container">
    <div class="text-center font-weight-bold col-8 mx-auto">
        <span id="question"></span>
    </div>
    <div class="d-grid gap-2 col-4 mx-auto">
        <button type="button" class="btn btn-primary btn-sm p-1" id="answer1"></button>
        <button type="button" class="btn btn-primary btn-sm" id="answer2"></button>
        <button type="button" class="btn btn-primary btn-sm" id="answer3"></button>
        <button type="button" class="btn btn-primary btn-sm" id="answer4"></button>
        <div class="text-center" id="score">Score: 0</div>
    </div>
    </div>
    <script src="main.js"></script>
</body>
</html>

关键优化点

  • 避免重复绑定事件,解决多次执行处理函数的问题
  • 用独立变量保存当前正确按钮ID,彻底避免全局数组被覆盖的干扰
  • 使用标准洗牌算法,保证答案顺序随机的可靠性
  • 错误点击时同步高亮正确答案,优化用户体验

内容的提问来源于stack exchange,提问作者Darren Revell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 12:49:55