
本文旨在解决JavaScript测验游戏中常见的积分重复计算问题,通过优化事件监听机制,特别是采用HTML表单的submit事件而非重复添加click事件,来构建一个更健壮、高效的测验系统。文章将详细阐述问题的根源,并提供一套基于表单提交的解决方案,包括HTML结构、JavaScript逻辑及相关API的运用,确保积分和题目计数准确无误。
1. 问题分析:为什么积分会重复计算?
在开发基于javascript的测验游戏时,一个常见的陷阱是由于事件监听器管理不当导致积分或计数重复增加。原始代码中,elegirrespuesta() 函数在每次调用 iterarjuego() 时都会为每个选项按钮重新添加 click 事件监听器。这意味着,当用户回答完第一道题并进入下一题时,新的监听器会被添加到旧的监听器之上。如果 iterarjuego() 被调用了 n 次,那么每个选项按钮上就会有 n 个 click 监听器。
当用户点击一个选项时,所有这些重复的监听器都会被触发,导致 funAnalizar() 函数被调用多次,进而 respCorrecta() 或 respIncorrecta() 函数也会被多次执行。例如,在第二道题时,每个点击会触发两次事件,使得积分和题目计数都增加两倍,从而出现积分重复计算的错误。
2. 解决方案:利用表单提交事件优化事件处理
为了解决上述问题,我们可以采用更优雅且高效的事件处理方式:将所有选项包装在一个HTML
:所有选项都使用 name=’opt’,这样 IO.opt.value 就可以直接获取被选中的值。:这是一个默认类型为 submit 的按钮,点击它会触发表单的 submit 事件。
2.2 JavaScript逻辑重构
在JavaScript中,我们将利用 document.forms 和 form.elements 接口来简化对表单元素的访问。
2.2.1 访问表单元素
document.forms 允许通过ID或name属性直接访问页面中的表单。HTMLFormElement.elements 属性则返回一个 HTMLFormControlsCollection,其中包含了表单中的所有控件。
// 获取表单元素 const QA = document.forms.QA; // 获取表单内的所有控件 const IO = QA.elements; // 直接通过name或id访问控件 const question = IO.question; // const score = IO.score; // // 选项的label元素,用于显示文本 const opt1 = IO.optA.nextElementSibling; const opt2 = IO.optB.nextElementSibling; const opt3 = IO.optC.nextElementSibling; const opt4 = IO.optD.nextElementSibling;
2.2.2 测验数据结构
测验题目数据可以保持类似的数组对象结构,但为了更好地与HTML中的 value 属性对应,可以将正确答案存储为选项的 value (例如 ‘optA’)。
let qID = 0; // 当前题目索引 let totalP = 0; // 总得分 let totalQ = 0; // 总题目数 // 测验题目数组 const qArray = [{ qID: 0, ques: "Que significa AI en Japonés?", optA: 'amor', optB: 'carcel', optC: 'pizza', optD: 'caja', right: 'optA' // 正确答案对应选项的value }, { qID: 1, ques: "Cual es el hiragana 'ME' ?", optA: 'ぬ', optB: 'ね', optC: 'ぐ', optD: 'め', right: 'optD' }, { qID: 2, ques: "En hiragana: DESAYUNO , ALMUERZO , CENA ?", optA: 'ぬ', optB: 'ね', optC: 'ぐ', optD: 'め', right: 'optB' }, { qID: 3, ques: "Como se dice madre y padre ?", optA: 'chichi hana', optB: 'hana mitsu', optC: 'kirei chichi', optD: 'undo chichi', right: 'optC' }, { qID: 4, ques: "Que significa きれい ?", optA: 'rey y reina', optB: 'lindo y linda', optC: 'hermoso y hermosa', optD: 'salvaje y saldro', right: 'optB' }];
2.2.3 核心函数实现
a. quiz() 函数:加载题目
这个函数负责根据当前 qID 更新页面上的问题和选项文本,并清除之前选中的电台按钮。
function quiz() { // 更新问题文本 question.textContent = (qID + 1) + '. ' + qArray[qID].ques; // 更新选项文本 opt1.textContent = qArray[qID].optA; opt2.textContent = qArray[qID].optB; opt3.textContent = qArray[qID].optC; opt4.textContent = qArray[qID].optD; // 遍历所有名为 'opt' 的radio按钮,取消选中状态 [...IO.opt].forEach(o => { if (o.checked) { o.checked = false; } }); }
b. evaluate() 函数:处理表单提交
这是核心的事件处理函数,它绑定到表单的 submit 事件。
// 绑定表单的onsubmit事件 QA.onsubmit = evaluate; function evaluate(e) { // 阻止表单的默认提交行为,防止页面刷新 e.preventDefault(); // 获取被选中的radio按钮的value let selected = IO.opt.value; // 判断答案是否正确 if (selected === qArray[qID].right) { correct(); } else { wrong(); } }
注意事项:
e.preventDefault() 是至关重要的一步。如果省略,表单会尝试将数据发送到服务器,导致页面刷新,从而中断测验流程。IO.opt.value 会自动获取 name=’opt’ 的一组电台按钮中被选中的那个的 value 属性值。
c. correct() 和 wrong() 函数:更新分数和题目
这两个函数负责更新分数、题目计数,并加载下一道题。
function correct() { totalP++; // 积分增加 totalQ++; // 题目数增加 score.textContent = totalP + " / " + totalQ; // 更新显示 qID++; // 移动到下一题 // 如果所有题目都已回答,隐藏“Next”按钮 if (qID >= qArray.length) { return IO.next.style.display = 'none'; } quiz(); // 加载下一题 } function wrong() { totalQ++; // 题目数增加(不加分) score.textContent = totalP + " / " + totalQ; // 更新显示 qID++; // 移动到下一题 // 如果所有题目都已回答,隐藏“Next”按钮 if (qID >= qArray.length) { return IO.next.style.display = 'none'; } quiz(); // 加载下一题 }
2.2.4 启动测验
最后,在页面加载完成后,调用 quiz() 函数来显示第一道题。
// 页面加载后启动测验 quiz();
3. 完整代码示例
将上述HTML和JavaScript代码整合后,得到一个功能完善且避免了重复计分问题的测验游戏。
JavaScript测验游戏 html { font: 300 3ch/1.2 'Segoe UI' } #score { font-size: 1.25rem; } #score::before { content: 'Score: ' } ol { list-style: lower-latin; margin-top: 0 } input, button { font: inherit } li { margin-bottom: 8px; } button { display: inline-flex; align-items: center; padding: 0 0.5rem; cursor: pointer }const QA = document.forms.QA; const IO = QA.elements; const question = IO.question; const score = IO.score; const opt1 = IO.optA.nextElementSibling; const opt2 = IO.optB.nextElementSibling; const opt3 = IO.optC.nextElementSibling; const opt4 = IO.optD.nextElementSibling; let qID = 0; let totalP = 0; let totalQ = 0; function quiz() { question.textContent = (qID + 1) + '. ' + qArray[qID].ques; opt1.textContent = qArray[qID].optA; opt2.textContent = qArray[qID].optB; opt3.textContent = qArray[qID].optC; opt4.textContent = qArray[qID].optD; [...IO.opt].forEach(o => { if (o.checked) { o.checked = false; } }); } QA.onsubmit = evaluate; function evaluate(e) { e.preventDefault(); let selected = IO.opt.value; if (selected === qArray[qID].right) { correct(); } else { wrong(); } } function correct() { totalP++; totalQ++; score.textContent = totalP + " / " + totalQ; qID++; if (qID >= qArray.length) { return IO.next.style.display = 'none'; } quiz(); } function wrong() { totalQ++; score.textContent = totalP + " / " + totalQ; qID++; if (qID >= qArray.length) { return IO.next.style.display = 'none'; } quiz(); } const qArray = [{ qID: 0, ques: "Que significa AI en Japonés?", optA: 'amor', optB: 'carcel', optC: 'pizza', optD: 'caja', right: 'optA' }, { qID: 1, ques: "Cual es el hiragana 'ME' ?", optA: 'ぬ', optB: 'ね', optC: 'ぐ', optD: 'め', right: 'optD' }, { qID: 2, ques: "En hiragana: DESAYUNO , ALMUERZO , CENA ?", optA: 'ぬ', optB: 'ね', optC: 'ぐ', optD: 'め', right: 'optB' }, { qID: 3, ques: "Como se dice madre y padre ?", optA: 'chichi hana', optB: 'hana mitsu', optC: 'kirei chichi', optD: 'undo chichi', right: 'optC' }, { qID: 4, ques: "Que significa きれい ?", optA: 'rey y reina', optB: 'lindo y linda', optC: 'hermoso y hermosa', optD: 'salvaje y saldro', right: 'optB' }]; quiz();
4. 总结与最佳实践
通过将测验逻辑从多个 click 事件监听器重构为单个 form 的 submit 事件监听器,我们成功解决了JavaScript测验中积分重复计算的问题。这种方法不仅代码更简洁、更易于维护,而且也遵循了Web开发的最佳实践:
避免重复添加事件监听器: 确保事件监听器只被添加一次,或者在不再需要时正确移除。利用HTML语义化: 使用 使用 e.preventDefault(): 在处理表单提交事件时,始终记得阻止其默认行为,以避免不必要的页面刷新。集中式事件处理: 对于一组相关的UI元素(如表单中的多个选项),使用事件委托或在父元素上监听事件是一种高效的方法。
掌握这些技巧将有助于开发更健壮、性能更优的Web应用程序。
以上就是JavaScript测验游戏积分重复计算问题的解决方案与优化实践的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1577591.html
微信扫一扫
支付宝扫一扫