单选按钮点击后禁用其他输入功能异常及生产级代码优化咨询
问题修复与生产级测验代码优化
一、问题修复:单选按钮点击后禁用失效的解决
问题根源
你的代码大概率只在选中正确答案的逻辑分支里编写了禁用其余输入的代码,而点击错误答案时没有执行相同的禁用操作,导致功能失效。
修复后的完整代码
HTML部分
<div class="quiz-container"> <h3>问题:以下哪个是JavaScript的原始数据类型?</h3> <div class="options"> <label> <input type="radio" name="answer" value="object" data-is-correct="false"> Object </label> <label> <input type="radio" name="answer" value="array" data-is-correct="false"> Array </label> <label> <input type="radio" name="answer" value="string" data-is-correct="true"> String </label> <label> <input type="radio" name="answer" value="function" data-is-correct="false"> Function </label> </div> <p id="feedback"></p> </div>
JavaScript部分
// 获取所有单选按钮和反馈元素 const radioButtons = document.querySelectorAll('input[name="answer"]'); const feedbackElement = document.getElementById('feedback'); // 为每个单选按钮绑定点击事件 radioButtons.forEach(radio => { radio.addEventListener('click', handleAnswerSelect); }); function handleAnswerSelect(e) { const selectedRadio = e.target; const isCorrect = selectedRadio.dataset.isCorrect === 'true'; // 核心修复:无论正确错误,先禁用所有单选按钮 radioButtons.forEach(btn => { btn.disabled = true; // 给选中的选项添加样式标识 if (btn === selectedRadio) { btn.parentElement.classList.add('selected'); } // 给正确答案添加标识(可选) if (btn.dataset.isCorrect === 'true') { btn.parentElement.classList.add('correct'); } }); // 显示反馈信息 if (isCorrect) { feedbackElement.textContent = '回答正确!'; feedbackElement.style.color = 'green'; } else { feedbackElement.textContent = '回答错误,正确答案是String!'; feedbackElement.style.color = 'red'; } }
修复说明
- 把禁用所有单选按钮的逻辑从正确答案的分支中抽离出来,放在事件处理函数的最前面,确保无论用户选对选错,都会执行禁用操作。
- 使用
data-is-correct属性存储正确答案标识,避免硬编码判断,更灵活。
二、生产级代码优化方案
1. 数据驱动设计
将题目、选项、正确答案等数据抽离为独立的配置对象,便于维护和扩展:
const quizData = { question: '以下哪个是JavaScript的原始数据类型?', options: [ { value: 'object', text: 'Object', isCorrect: false }, { value: 'array', text: 'Array', isCorrect: false }, { value: 'string', text: 'String', isCorrect: true }, { value: 'function', text: 'Function', isCorrect: false } ] }; // 动态渲染题目和选项 function renderQuiz(quizData) { const container = document.querySelector('.quiz-container'); container.innerHTML = ` <h3>${quizData.question}</h3> <div class="options"> ${quizData.options.map(opt => ` <label> <input type="radio" name="answer" value="${opt.value}" data-is-correct="${opt.isCorrect}"> ${opt.text} </label> `).join('')} </div> <p id="feedback"></p> `; // 重新绑定事件 bindEventListeners(); } renderQuiz(quizData);
2. 模块化封装
将测验逻辑封装为独立的模块,避免全局变量污染:
// quizModule.js export class Quiz { constructor(containerSelector, quizData) { this.container = document.querySelector(containerSelector); this.quizData = quizData; this.feedbackElement = null; // 校验容器是否存在 if (!this.container) throw new Error('测验容器不存在'); this.init(); } init() { this.render(); this.bindEvents(); } render() { this.container.innerHTML = ` <h3>${this.quizData.question}</h3> <div class="options"> ${this.quizData.options.map(opt => ` <label class="option-label"> <input type="radio" name="quiz-answer" value="${opt.value}" data-is-correct="${opt.isCorrect}"> ${opt.text} </label> `).join('')} </div> <p class="feedback"></p> `; this.feedbackElement = this.container.querySelector('.feedback'); } bindEvents() { // 使用事件委托替代逐个绑定,提升性能 this.container.addEventListener('click', (e) => { if (e.target.type === 'radio' && e.target.name === 'quiz-answer') { this.handleAnswerSelect(e); } }); } handleAnswerSelect(e) { const selectedRadio = e.target; const isCorrect = selectedRadio.dataset.isCorrect === 'true'; const allRadios = this.container.querySelectorAll('input[name="quiz-answer"]'); // 禁用所有选项 allRadios.forEach(radio => { radio.disabled = true; const label = radio.closest('.option-label'); if (radio === selectedRadio) label.classList.add('selected'); if (radio.dataset.isCorrect === 'true') label.classList.add('correct'); }); // 显示反馈 const correctOption = this.quizData.options.find(opt => opt.isCorrect).text; this.feedbackElement.textContent = isCorrect ? '回答正确!' : `回答错误,正确答案是${correctOption}!`; this.feedbackElement.className = `feedback ${isCorrect ? 'correct-feedback' : 'error-feedback'}`; } } // 使用模块 import { Quiz } from './quizModule.js'; const quizData = { /* 题目数据 */ }; new Quiz('.quiz-container', quizData);
3. 样式与逻辑分离
将样式写在独立的CSS文件中,避免内联样式:
.quiz-container { max-width: 600px; margin: 2rem auto; padding: 1rem; font-family: Arial, sans-serif; } .option-label { display: block; margin: 0.5rem 0; padding: 0.5rem; border-radius: 4px; cursor: pointer; transition: background-color 0.2s; } .option-label:hover { background-color: #f5f5f5; } .option-label.selected { background-color: #e0e0e0; } .option-label.correct { background-color: #d4edda; color: #155724; } .feedback { margin-top: 1rem; padding: 0.5rem; border-radius: 4px; } .correct-feedback { background-color: #d4edda; color: #155724; } .error-feedback { background-color: #f8d7da; color: #721c24; }
4. 可访问性优化
- 确保每个单选按钮都有对应的标签关联,屏幕阅读器可识别。
- 为禁用的单选按钮添加
aria-disabled="true"属性。 - 反馈信息添加
role="alert",让屏幕阅读器及时读取:
<p class="feedback" role="alert"></p>
5. 错误处理与边界情况
- 在模块构造函数中校验容器是否存在,避免无意义的执行。
- 校验题目数据的完整性,比如检查
options数组是否为空、是否存在正确答案。 - 防止重复触发事件,在渲染前清空容器内的旧元素和事件监听。
内容的提问来源于stack exchange,提问作者naman
相关产品推荐
相关产品推荐

