JavaScript测验应用动态生成题目出现跳题漏题问题求解
问题根源
跳题是重复绑定点击事件导致的:
- 你在
renderQuestion函数中每次渲染题目时,都会用$('.btn').click()给所有答案按钮追加新的点击监听器,jQuery的click方法不会覆盖旧的同类型事件,只会持续累加绑定的处理函数。 - 执行流程完全复现你遇到的现象:
- 页面加载完成点击开始,渲染第1题(数组下标0),给按钮绑定1个点击事件
- 点击第1题答案,触发1次
checkAnswer,下标自增到1,渲染第2题,此时给按钮追加第2个点击事件,每个按钮累计2个事件 - 点击第2题答案时会连续触发2次
checkAnswer:第一次执行后下标到2,渲染第3题同时追加第3个事件;第二次执行时下标已经是2,判题后下标自增到3,直接渲染第4题,第3题刚渲染就被覆盖,用户看不到 - 点击第4题答案时,按钮已经累计4个点击事件,会连续触发4次处理函数,直接跳过第5题,还会因为下标超出数组长度报读取undefined的错误。
修复方案
- 绑定新事件前先解绑旧事件,避免一次点击触发多次处理逻辑;更稳妥的方式是每次渲染题目时动态生成选项按钮,从根源上避免重复绑定问题,同时适配不同数量的选项(你现有代码固定渲染4个选项,第4题的第5个选项
Market Garden会被漏渲染) - 增加边界判断:当题目下标等于题库总长度时,终止答题流程,不要继续渲染题目,避免数组越界报错
修复后完整JS代码
const questions = [ { question: "Where was the first attempted allied invasion of France?", choices: ['Normandy', 'Nice', 'Dieppe', "Bourdeaux"], answer: "Dieppe" }, { question: "Which American general was in charge of the pacific campaign?", choices: ["George Patton", "Omar Bradley", "George Marshall", "Douglas MacArthur"], answer: "Douglas MacArthur" }, { question: "When was VE day?", choices: ["April", "May", "June", "July"], answer: "May" }, { question: "Which of these was considered the largest tank battle in history?", choices: ["Battle of the Bulge", "D-Day", "Kursk", "Stalingrad", "Market Garden"], answer: "Kursk" }, { question: "When did the war start?", choices: ["1939", "1938", "1941", "1944"], answer: "1939" } ] let questionIndex = 0; // 开始游戏 const startGame = () => { $('.start-btn').hide() $('.game-header').hide() $('.container').show(); renderQuestion() } // 渲染当前题目 const renderQuestion = () => { const currentQuestion = questions[questionIndex]; // 渲染题干 $('#question').text(currentQuestion.question); const answerWrap = $('.answers'); // 清空旧选项 answerWrap.empty(); // 动态生成所有选项按钮 currentQuestion.choices.forEach(choice => { const choiceBtn = $(`<button class="btn">${choice}</button>`); // 绑定点击事件,因为每次都是新生成的按钮,不会有重复绑定问题 choiceBtn.click(function() { checkAnswer($(this).text()); }) answerWrap.append(choiceBtn); }) } // 校验答案 const checkAnswer = (response) => { if (response === questions[questionIndex].answer) { window.alert('CORRECT!') } else { window.alert('INCORRECT!') } questionIndex++ // 所有题目答完,执行结束逻辑 if (questionIndex >= questions.length) { alert('Quiz completed!'); // 这里可以替换成你自己的算分、展示高分榜逻辑 return; } // 渲染下一题 renderQuestion() } $('.start-btn').click(startGame)
最小改动方案
如果你不想改成动态生成选项的写法,只需要在原有renderQuestion的事件绑定前加解绑语句即可,修改后的事件绑定部分代码如下:
// 先解绑所有旧的click事件,再绑定新事件 $('.btn').off('click').click(function () { let response = $(this).text() checkAnswer(response) })
注意这种写法仍然固定渲染4个选项,第4题的第5个选项不会显示,建议优先用动态生成选项的方案。
内容的提问来源于stack exchange,提问作者Ted
相关产品推荐
相关产品推荐

