实战项目4:问答系统
项目介绍
在这个项目中,我们将创建一个功能完整的问答系统,该系统允许用户回答一系列问题,并在完成后显示得分和结果反馈。这个项目将帮助我们学习JavaScript的状态管理、DOM操作、事件处理和定时器等核心概念。
项目需求
- 显示当前问题和选项
- 支持多选题和单选题
- 显示当前问题的序号和总题数
- 支持前进/后退导航
- 支持跳过问题
- 显示倒计时功能
- 支持实时计分
- 完成后显示详细的结果报告
- 显示正确答案和用户的选择
- 支持重新开始测验
- 页面布局简洁美观,响应式设计
技术栈
- HTML5
- CSS3
- JavaScript (ES6+)
项目结构
quiz-system-project/
├── index.html # 主页面
├── styles.css # 样式文件
└── script.js # JavaScript文件实现步骤
1. 创建HTML结构
首先,我们需要创建HTML结构,包括问答系统的各个组件:标题、进度条、问题显示、选项区域、导航按钮和结果页面。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>问答系统</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="quiz-container">
<div class="quiz-header">
<h1 id="quiz-title">JavaScript知识问答</h1>
<div class="quiz-info">
<div class="question-counter">
<span id="current-question">1</span> / <span id="total-questions">0</span>
</div>
<div class="timer">
<span id="time-remaining">60</span>秒
</div>
</div>
</div>
<!-- 进度条 -->
<div class="progress-container">
<div class="progress-bar" id="progress-bar"></div>
</div>
<!-- 问题区域 -->
<div class="question-section" id="question-section">
<div class="question" id="question">问题将在这里显示</div>
<!-- 选项区域 -->
<div class="options-container" id="options-container"></div>
</div>
<!-- 导航按钮 -->
<div class="navigation-buttons">
<button id="prev-btn" class="nav-btn" disabled>上一题</button>
<button id="next-btn" class="nav-btn primary">下一题</button>
<button id="submit-btn" class="nav-btn submit-btn" style="display: none;">提交</button>
</div>
<!-- 结果页面 -->
<div class="results-section" id="results-section" style="display: none;">
<h2>测验结果</h2>
<div class="score-card">
<div class="final-score" id="final-score">0</div>
<div class="score-text">
<span id="correct-answers">0</span> / <span id="total-questions-result">0</span> 正确
</div>
<div class="grade" id="grade">优秀</div>
</div>
<!-- 详细结果 -->
<div class="detailed-results" id="detailed-results"></div>
<!-- 重新开始按钮 -->
<button id="restart-btn" class="nav-btn primary">重新开始</button>
</div>
</div>
<script src="script.js"></script>
</body>
</html>2. 添加CSS样式
接下来,我们需要添加CSS样式,使问答系统看起来更加美观和易用。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background-color: #f5f5f5;
color: #333;
line-height: 1.6;
}
.quiz-container {
background-color: white;
border-radius: 10px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
padding: 20px;
max-width: 800px;
width: 100%;
margin: 50px auto;
}
/* 头部样式 */
.quiz-header {
text-align: center;
margin-bottom: 20px;
}
#quiz-title {
color: #2c3e50;
font-size: 28px;
margin-bottom: 15px;
}
.quiz-info {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #ecf0f1;
padding: 10px 20px;
border-radius: 5px;
font-weight: bold;
}
.question-counter {
color: #34495e;
}
.timer {
color: #e74c3c;
font-size: 18px;
}
/* 进度条样式 */
.progress-container {
background-color: #ecf0f1;
border-radius: 10px;
height: 10px;
margin-bottom: 20px;
overflow: hidden;
}
.progress-bar {
background-color: #3498db;
height: 100%;
width: 0%;
transition: width 0.3s ease;
border-radius: 10px;
}
/* 问题区域样式 */
.question-section {
margin-bottom: 20px;
}
.question {
font-size: 20px;
font-weight: bold;
margin-bottom: 20px;
color: #2c3e50;
line-height: 1.4;
}
/* 选项区域样式 */
.options-container {
display: flex;
flex-direction: column;
gap: 12px;
}
.option {
background-color: #f8f9fa;
border: 2px solid #e9ecef;
border-radius: 8px;
padding: 15px;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
user-select: none;
}
.option:hover {
background-color: #e9ecef;
transform: translateX(5px);
}
.option.selected {
background-color: #d1ecf1;
border-color: #3498db;
}
.option.correct {
background-color: #d4edda;
border-color: #28a745;
}
.option.incorrect {
background-color: #f8d7da;
border-color: #dc3545;
}
.option input[type="radio"],
.option input[type="checkbox"] {
margin-right: 15px;
transform: scale(1.2);
}
.option-label {
font-size: 16px;
cursor: pointer;
}
/* 导航按钮样式 */
.navigation-buttons {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 30px;
}
.nav-btn {
background-color: #6c757d;
color: white;
border: none;
padding: 12px 20px;
font-size: 16px;
border-radius: 5px;
cursor: pointer;
transition: all 0.3s ease;
font-weight: bold;
min-width: 120px;
}
.nav-btn:hover:not(:disabled) {
background-color: #5a6268;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.nav-btn:active:not(:disabled) {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.nav-btn:disabled {
background-color: #e9ecef;
color: #6c757d;
cursor: not-allowed;
opacity: 0.7;
}
.nav-btn.primary {
background-color: #3498db;
}
.nav-btn.primary:hover:not(:disabled) {
background-color: #2980b9;
}
.submit-btn {
background-color: #28a745;
}
.submit-btn:hover:not(:disabled) {
background-color: #218838;
}
/* 结果页面样式 */
.results-section {
text-align: center;
padding: 30px 0;
}
.results-section h2 {
color: #2c3e50;
margin-bottom: 30px;
font-size: 28px;
}
.score-card {
background-color: #f8f9fa;
border-radius: 10px;
padding: 30px;
margin-bottom: 30px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.final-score {
font-size: 64px;
font-weight: bold;
color: #3498db;
margin-bottom: 10px;
}
.score-text {
font-size: 20px;
color: #6c757d;
margin-bottom: 15px;
}
.grade {
font-size: 24px;
font-weight: bold;
padding: 10px 20px;
border-radius: 20px;
display: inline-block;
}
.grade.excellent {
background-color: #d4edda;
color: #155724;
}
.grade.good {
background-color: #d1ecf1;
color: #0c5460;
}
.grade.average {
background-color: #fff3cd;
color: #856404;
}
.grade.poor {
background-color: #f8d7da;
color: #721c24;
}
/* 详细结果样式 */
.detailed-results {
margin-top: 30px;
text-align: left;
}
.result-item {
background-color: #f8f9fa;
border-radius: 8px;
padding: 20px;
margin-bottom: 15px;
border-left: 5px solid #3498db;
}
.result-item.correct {
border-left-color: #28a745;
}
.result-item.incorrect {
border-left-color: #dc3545;
}
.result-question {
font-weight: bold;
margin-bottom: 10px;
color: #2c3e50;
}
.result-options {
margin-left: 20px;
}
.result-option {
margin-bottom: 5px;
padding-left: 5px;
}
.result-option.correct {
color: #28a745;
font-weight: bold;
}
.result-option.incorrect {
color: #dc3545;
text-decoration: line-through;
}
.result-option.selected {
font-style: italic;
}
.result-explanation {
margin-top: 10px;
font-size: 14px;
color: #6c757d;
font-style: italic;
}
/* 响应式设计 */
@media (max-width: 768px) {
.quiz-container {
margin: 20px;
padding: 15px;
}
#quiz-title {
font-size: 24px;
}
.quiz-info {
flex-direction: column;
gap: 10px;
}
.question {
font-size: 18px;
}
.navigation-buttons {
flex-direction: column;
gap: 15px;
}
.nav-btn {
width: 100%;
}
.final-score {
font-size: 48px;
}
}
@media (max-width: 480px) {
.quiz-container {
margin: 10px;
padding: 10px;
}
#quiz-title {
font-size: 20px;
}
.question {
font-size: 16px;
}
.option {
padding: 12px;
}
.final-score {
font-size: 36px;
}
}2. 编写JavaScript逻辑
最后,我们需要编写JavaScript逻辑,实现问答系统的所有功能。
// 问题数据
const quizData = [
{
question: "以下哪个不是JavaScript的基本数据类型?",
type: "single",
options: [
{ text: "String", correct: false },
{ text: "Number", correct: false },
{ text: "Boolean", correct: false },
{ text: "Object", correct: true }
],
explanation: "JavaScript的基本数据类型包括String、Number、Boolean、Null、Undefined、Symbol和BigInt,而Object是引用数据类型。"
},
{
question: "以下哪些是JavaScript的循环语句?",
type: "multiple",
options: [
{ text: "for", correct: true },
{ text: "while", correct: true },
{ text: "do-while", correct: true },
{ text: "loop", correct: false }
],
explanation: "JavaScript的循环语句包括for、while、do-while和for...of、for...in等,但没有loop语句。"
},
{
question: "以下哪个方法可以用来添加事件监听器?",
type: "single",
options: [
{ text: "addEventListener", correct: true },
{ text: "attachEvent", correct: false },
{ text: "onclick", correct: false },
{ text: "addEvent", correct: false }
],
explanation: "addEventListener是标准的事件监听器添加方法,attachEvent是旧版IE浏览器的方法,onclick是事件属性,addEvent不是标准方法。"
},
{
question: "以下哪些是JavaScript的数组方法?",
type: "multiple",
options: [
{ text: "push", correct: true },
{ text: "pop", correct: true },
{ text: "shift", correct: true },
{ text: "slice", correct: true },
{ text: "splice", correct: true },
{ text: "concat", correct: true }
],
explanation: "以上所有方法都是JavaScript的数组方法,用于数组的增删改查操作。"
},
{
question: "以下哪个关键字用于创建类?",
type: "single",
options: [
{ text: "class", correct: true },
{ text: "function", correct: false },
{ text: "object", correct: false },
{ text: "constructor", correct: false }
],
explanation: "class关键字用于创建类,function用于创建函数,object不是关键字,constructor是类中的构造函数。"
},
{
question: "以下哪些是JavaScript的异步编程方法?",
type: "multiple",
options: [
{ text: "setTimeout", correct: true },
{ text: "setInterval", correct: true },
{ text: "Promise", correct: true },
{ text: "async/await", correct: true },
{ text: "fetch", correct: true }
],
explanation: "以上所有方法都是JavaScript的异步编程方法,用于处理异步操作。"
},
{
question: "以下哪个方法可以用来解析JSON字符串?",
type: "single",
options: [
{ text: "JSON.parse()", correct: true },
{ text: "JSON.stringify()", correct: false },
{ text: "JSON.decode()", correct: false },
{ text: "JSON.encode()", correct: false }
],
explanation: "JSON.parse()用于将JSON字符串解析为JavaScript对象,JSON.stringify()用于将JavaScript对象转换为JSON字符串。"
},
{
question: "以下哪些是JavaScript的DOM选择器方法?",
type: "multiple",
options: [
{ text: "getElementById", correct: true },
{ text: "getElementsByClassName", correct: true },
{ text: "getElementsByTagName", correct: true },
{ text: "querySelector", correct: true },
{ text: "querySelectorAll", correct: true }
],
explanation: "以上所有方法都是JavaScript的DOM选择器方法,用于选择DOM元素。"
}
];
// DOM元素
const currentQuestionElement = document.getElementById('current-question');
const totalQuestionsElement = document.getElementById('total-questions');
const timeRemainingElement = document.getElementById('time-remaining');
const progressBarElement = document.getElementById('progress-bar');
const questionElement = document.getElementById('question');
const optionsContainerElement = document.getElementById('options-container');
const prevBtnElement = document.getElementById('prev-btn');
const nextBtnElement = document.getElementById('next-btn');
const submitBtnElement = document.getElementById('submit-btn');
const questionSectionElement = document.getElementById('question-section');
const resultsSectionElement = document.getElementById('results-section');
const finalScoreElement = document.getElementById('final-score');
const correctAnswersElement = document.getElementById('correct-answers');
const totalQuestionsResultElement = document.getElementById('total-questions-result');
const gradeElement = document.getElementById('grade');
const detailedResultsElement = document.getElementById('detailed-results');
const restartBtnElement = document.getElementById('restart-btn');
// 测验状态
let currentQuestionIndex = 0;
let score = 0;
let userAnswers = [];
let timeRemaining = 60;
let timer = null;
let quizCompleted = false;
// 初始化测验
function initQuiz() {
// 初始化用户答案数组
userAnswers = new Array(quizData.length).fill(null);
// 设置总题数
totalQuestionsElement.textContent = quizData.length;
totalQuestionsResultElement.textContent = quizData.length;
// 显示第一个问题
showQuestion(currentQuestionIndex);
// 启动计时器
startTimer();
}
// 显示问题
function showQuestion(index) {
// 更新当前问题索引
currentQuestionIndex = index;
// 更新问题计数器
currentQuestionElement.textContent = index + 1;
// 更新进度条
const progressPercentage = ((index + 1) / quizData.length) * 100;
progressBarElement.style.width = `${progressPercentage}%`;
// 获取当前问题数据
const currentQuestion = quizData[index];
// 显示问题
questionElement.textContent = currentQuestion.question;
// 清空选项容器
optionsContainerElement.innerHTML = '';
// 生成选项
currentQuestion.options.forEach((option, optionIndex) => {
const optionElement = document.createElement('div');
optionElement.className = 'option';
// 根据问题类型创建不同的输入元素
let inputElement;
if (currentQuestion.type === 'single') {
inputElement = document.createElement('input');
inputElement.type = 'radio';
inputElement.name = 'question' + index;
inputElement.value = optionIndex;
} else {
inputElement = document.createElement('input');
inputElement.type = 'checkbox';
inputElement.name = 'question' + index;
inputElement.value = optionIndex;
}
// 如果用户已经回答过这个问题,恢复选中状态
if (userAnswers[index] !== null) {
if (currentQuestion.type === 'single') {
inputElement.checked = userAnswers[index] === optionIndex;
} else {
inputElement.checked = userAnswers[index].includes(optionIndex);
}
}
// 创建选项标签
const labelElement = document.createElement('label');
labelElement.className = 'option-label';
labelElement.textContent = option.text;
// 将输入元素和标签添加到选项容器
optionElement.appendChild(inputElement);
optionElement.appendChild(labelElement);
// 添加选项到选项容器
optionsContainerElement.appendChild(optionElement);
// 添加选项点击事件
optionElement.addEventListener('click', () => {
handleOptionSelect(optionElement, inputElement, currentQuestion.type);
});
// 添加输入元素的change事件
inputElement.addEventListener('change', () => {
handleOptionSelect(optionElement, inputElement, currentQuestion.type);
});
});
// 更新导航按钮状态
updateNavigationButtons();
}
// 处理选项选择
function handleOptionSelect(optionElement, inputElement, questionType) {
// 获取当前问题的所有选项
const allOptions = optionsContainerElement.querySelectorAll('.option');
const allInputs = optionsContainerElement.querySelectorAll('input');
// 移除所有选项的选中状态
allOptions.forEach(opt => opt.classList.remove('selected'));
// 处理单选题
if (questionType === 'single') {
// 只选中当前选项
optionElement.classList.add('selected');
// 保存用户答案
userAnswers[currentQuestionIndex] = parseInt(inputElement.value);
}
// 处理多选题
else {
// 切换当前选项的选中状态
optionElement.classList.toggle('selected');
// 获取所有选中的选项
const selectedInputs = optionsContainerElement.querySelectorAll('input:checked');
const selectedValues = Array.from(selectedInputs).map(input => parseInt(input.value));
// 保存用户答案
userAnswers[currentQuestionIndex] = selectedValues;
}
}
// 更新导航按钮状态
function updateNavigationButtons() {
// 更新上一题按钮状态
prevBtnElement.disabled = currentQuestionIndex === 0;
// 更新下一题/提交按钮状态
if (currentQuestionIndex === quizData.length - 1) {
nextBtnElement.style.display = 'none';
submitBtnElement.style.display = 'inline-block';
} else {
nextBtnElement.style.display = 'inline-block';
submitBtnElement.style.display = 'none';
}
}
// 开始计时器
function startTimer() {
// 清除之前的计时器
if (timer) {
clearInterval(timer);
}
// 重置时间
timeRemaining = 60;
timeRemainingElement.textContent = timeRemaining;
// 启动计时器
timer = setInterval(() => {
timeRemaining--;
timeRemainingElement.textContent = timeRemaining;
// 如果时间用完,自动提交
if (timeRemaining <= 0) {
clearInterval(timer);
submitQuiz();
}
// 更新计时器样式
if (timeRemaining <= 10) {
timeRemainingElement.style.color = '#dc3545';
timeRemainingElement.style.fontWeight = 'bold';
} else {
timeRemainingElement.style.color = '';
timeRemainingElement.style.fontWeight = '';
}
}, 1000);
}
// 计算得分
function calculateScore() {
score = 0;
quizData.forEach((question, index) => {
const userAnswer = userAnswers[index];
// 如果用户没有回答,跳过
if (userAnswer === null) {
return;
}
// 处理单选题
if (question.type === 'single') {
if (question.options[userAnswer].correct) {
score++;
}
}
// 处理多选题
else {
// 检查用户的选择是否与正确答案完全匹配
const correctOptions = question.options
.map((option, i) => option.correct ? i : null)
.filter(i => i !== null);
// 检查长度是否相同
if (userAnswer.length === correctOptions.length) {
// 检查所有选项是否都正确
const allCorrect = userAnswer.every(answer => correctOptions.includes(answer));
if (allCorrect) {
score++;
}
}
}
});
return score;
}
// 获取等级
function getGrade(score, total) {
const percentage = (score / total) * 100;
if (percentage >= 90) {
return { text: '优秀', class: 'excellent' };
} else if (percentage >= 80) {
return { text: '良好', class: 'good' };
} else if (percentage >= 60) {
return { text: '及格', class: 'average' };
} else {
return { text: '不及格', class: 'poor' };
}
}
// 显示结果
function showResults() {
// 隐藏问题区域,显示结果区域
questionSectionElement.style.display = 'none';
resultsSectionElement.style.display = 'block';
// 停止计时器
if (timer) {
clearInterval(timer);
}
// 计算得分
const correctAnswers = calculateScore();
const totalQuestions = quizData.length;
const percentage = Math.round((correctAnswers / totalQuestions) * 100);
// 获取等级
const grade = getGrade(correctAnswers, totalQuestions);
// 更新结果显示
finalScoreElement.textContent = percentage + '%';
correctAnswersElement.textContent = correctAnswers;
totalQuestionsResultElement.textContent = totalQuestions;
gradeElement.textContent = grade.text;
gradeElement.className = `grade ${grade.class}`;
// 显示详细结果
showDetailedResults();
}
// 显示详细结果
function showDetailedResults() {
// 清空详细结果容器
detailedResultsElement.innerHTML = '';
// 遍历所有问题
quizData.forEach((question, index) => {
const userAnswer = userAnswers[index];
// 创建结果项
const resultItem = document.createElement('div');
resultItem.className = 'result-item';
// 检查答案是否正确
let isCorrect = false;
if (userAnswer !== null) {
if (question.type === 'single') {
isCorrect = question.options[userAnswer].correct;
} else {
const correctOptions = question.options
.map((option, i) => option.correct ? i : null)
.filter(i => i !== null);
isCorrect = userAnswer.length === correctOptions.length &&
userAnswer.every(answer => correctOptions.includes(answer));
}
}
// 添加正确/错误类
resultItem.classList.add(isCorrect ? 'correct' : 'incorrect');
// 创建问题元素
const questionElement = document.createElement('div');
questionElement.className = 'result-question';
questionElement.textContent = `${index + 1}. ${question.question}`;
// 创建选项容器
const optionsContainer = document.createElement('div');
optionsContainer.className = 'result-options';
// 添加选项到选项容器
question.options.forEach((option, optionIndex) => {
const optionElement = document.createElement('div');
optionElement.className = 'result-option';
// 检查选项是否正确
if (option.correct) {
optionElement.classList.add('correct');
}
// 检查选项是否被用户选中
let isSelected = false;
if (userAnswer !== null) {
if (question.type === 'single') {
isSelected = userAnswer === optionIndex;
} else {
isSelected = userAnswer.includes(optionIndex);
}
}
if (isSelected) {
optionElement.classList.add('selected');
// 如果选项被选中但不正确,添加错误类
if (!option.correct) {
optionElement.classList.add('incorrect');
}
}
// 设置选项文本
optionElement.textContent = option.text;
// 添加选项到选项容器
optionsContainer.appendChild(optionElement);
});
// 创建解释元素
const explanationElement = document.createElement('div');
explanationElement.className = 'result-explanation';
explanationElement.textContent = question.explanation;
// 将元素添加到结果项
resultItem.appendChild(questionElement);
resultItem.appendChild(optionsContainer);
resultItem.appendChild(explanationElement);
// 将结果项添加到详细结果容器
detailedResultsElement.appendChild(resultItem);
});
}
// 更新导航按钮
function updateNavigationButtons() {
// 更新上一题按钮状态
prevBtnElement.disabled = currentQuestionIndex === 0;
// 更新下一题/提交按钮状态
if (currentQuestionIndex === quizData.length - 1) {
nextBtnElement.style.display = 'none';
submitBtnElement.style.display = 'inline-block';
} else {
nextBtnElement.style.display = 'inline-block';
submitBtnElement.style.display = 'none';
}
}
// 导航到上一题
function goToPreviousQuestion() {
if (currentQuestionIndex > 0) {
currentQuestionIndex--;
showQuestion(currentQuestionIndex);
}
}
// 导航到下一题
function goToNextQuestion() {
if (currentQuestionIndex < quizData.length - 1) {
currentQuestionIndex++;
showQuestion(currentQuestionIndex);
}
}
// 提交测验
function submitQuiz() {
quizCompleted = true;
showResults();
}
// 重新开始测验
function restartQuiz() {
// 重置状态
currentQuestionIndex = 0;
score = 0;
userAnswers = [];
timeRemaining = 60;
quizCompleted = false;
// 显示问题区域,隐藏结果区域
questionSectionElement.style.display = 'block';
resultsSectionElement.style.display = 'none';
// 重新初始化测验
initQuiz();
}
// 添加事件监听器
prevBtnElement.addEventListener('click', goToPreviousQuestion);
nextBtnElement.addEventListener('click', goToNextQuestion);
submitBtnElement.addEventListener('click', submitQuiz);
restartBtnElement.addEventListener('click', restartQuiz);
// 初始化测验
initQuiz();功能说明
- 问题展示:显示当前问题和选项,支持单选题和多选题。
- 进度追踪:显示当前问题序号、总题数和进度条。
- 倒计时功能:每道题限时60秒,时间用完自动提交。
- 导航功能:支持前进/后退导航,方便用户修改答案。
- 实时反馈:选项被选中时会有视觉反馈。
- 自动计分:完成后自动计算得分和正确率。
- 详细结果:显示每道题的正确答案、用户选择和解释。
- 等级评定:根据得分评定等级(优秀、良好、及格、不及格)。
- 重新开始:支持重新开始测验。
- 响应式设计:适配不同屏幕尺寸,在手机和电脑上都能正常使用。
扩展功能
我们可以进一步扩展问答系统的功能,例如:
- 支持多种题型:填空题、判断题、简答题等。
- 支持随机出题:每次测验随机抽取一定数量的题目。
- 支持题目分类:按难度或知识点分类。
- 支持用户登录:保存用户的测验历史和成绩。
- 支持时间设置:允许管理员设置每道题的时间。
- 支持题目导入导出:支持从JSON或CSV文件导入题目。
- 支持图片和视频题目:允许在题目中插入图片和视频。
- 支持音效反馈:选择答案或完成测验时播放音效。
扩展功能示例:随机出题
// 扩展:随机出题功能
function getRandomQuestions(data, count) {
// 创建问题数据的副本
const questionsCopy = [...data];
const randomQuestions = [];
// 随机抽取指定数量的题目
for (let i = 0; i < count && questionsCopy.length > 0; i++) {
const randomIndex = Math.floor(Math.random() * questionsCopy.length);
randomQuestions.push(questionsCopy[randomIndex]);
questionsCopy.splice(randomIndex, 1);
}
return randomQuestions;
}
// 使用随机出题功能
const randomQuizData = getRandomQuestions(quizData, 5); // 随机抽取5道题扩展功能示例:多种题型支持
// 扩展:支持判断题
const quizDataWithTrueFalse = [
{
question: "JavaScript是一种编译型语言。",
type: "truefalse",
correct: false,
explanation: "JavaScript是一种解释型语言,不是编译型语言。"
}
];
// 在showQuestion函数中添加判断题处理
if (currentQuestion.type === 'truefalse') {
// 创建判断题选项
const trueOption = createOption('正确', 'true');
const falseOption = createOption('错误', 'false');
optionsContainerElement.appendChild(trueOption);
optionsContainerElement.appendChild(falseOption);
}项目运行
- 创建上述三个文件(index.html, styles.css, script.js)
- 在浏览器中打开index.html文件
- 开始使用问答系统
项目总结
通过这个问答系统项目,我们学习了:
- 如何使用JavaScript进行状态管理
- 如何处理不同类型的表单输入
- 如何使用DOM操作动态更新页面内容
- 如何使用定时器实现倒计时功能
- 如何实现复杂的导航逻辑
- 如何计算得分和生成结果报告
- 如何实现响应式设计
这个项目涵盖了JavaScript开发中的许多重要概念,为我们后续开发更复杂的应用打下了基础。
练习
- 添加填空题支持
- 实现随机出题功能
- 添加题目分类功能
- 实现时间设置功能
- 添加题目导入导出功能
- 实现用户登录功能
- 添加音效反馈功能
- 实现排行榜功能
扩展阅读
通过这个实战项目,我们已经掌握了JavaScript的状态管理和复杂交互逻辑,接下来我们将继续学习更复杂的JavaScript项目。