使用 HTML + JavaScript 实现在线考试系统

news2025/7/21 0:59:53

在现代的在线教育平台中,在线考试系统是不可或缺的一部分。本文将通过一个完整的示例,演示如何使用 HTML、CSS 和 JavaScript 构建一个支持多种题型的在线考试系统。

效果演示

image-20250528213340576

image-20250528213416003

image-20250528213449248

项目概述

本项目主要包含以下核心功能:

  • 支持4种常见题型:单选题、多选题、判断题、填空题
  • 答题卡导航功能
  • 实时计时器
  • 自动评分与结果反馈

页面结构与样式设计

创建 HTML 结构
<div class="container">
    <!-- 考试内容 -->
    <div class="exam-container">
        <!-- 标题和计时器 -->
        <div class="header">
            <h2>在线考试系统</h2>
            <div class="timer">剩余时间: <span id="time">30:00</span></div>
        </div>
        <!-- 题目 -->
        <div id="subject"></div>
        <!-- 导航按钮 -->
        <div class="navigation">
            <button id="prev-btn" disabled>上一题</button>
            <button id="next-btn">下一题</button>
            <button id="submit-btn" class="submit-btn">提交试卷</button>
        </div>
        <!-- 结果 -->
        <div id="result" class="result">
            <h2>考试结束</h2>
            <p>你的得分是: <span class="score" id="final-score">0</span></p>
            <p id="result-message"></p>
        </div>
    </div>
    <!-- 答题卡 -->
    <div class="answer-sheet">
        <h3>答题卡</h3>
        <div class="answer-buttons" id="answer-buttons"></div>
    </div>
</div>
设计 CSS 样式

整体布局

body {
    margin: 0;
    padding: 0;
    background-color: #f5f5f5;
}
.container {
    display: flex;
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
}
.exam-container {
    flex: 3;
    background-color: white;
    padding: 30px;
    border-radius: 10px;
    box-shadow: 0 0 10px rgba(0,0,0,0.1);
    margin-right: 20px;
}
.answer-sheet {
    flex: 1;
    background-color: white;
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 0 10px rgba(0,0,0,0.1);
    height: fit-content;
    position: sticky;
    top: 20px;
}

题目区域样式

.header {
    display: flex;
    justify-content: space-between;
    margin-bottom: 20px;
    padding-bottom: 10px;
    border-bottom: 1px solid #eee;
}
.timer {
    font-weight: bold;
    color: #e74c3c;
}
.question {
    margin-bottom: 20px;
    padding: 15px;
    background-color: #f9f9f9;
    border-radius: 5px;
}
.question h3 {
    margin-top: 0;
    color: #2c3e50;
}
.question-type {
    display: inline-block;
    padding: 2px 8px;
    background-color: #3498db;
    color: white;
    border-radius: 4px;
    font-size: 12px;
    margin-left: 10px;
}
.options {
    margin-left: 20px;
}
.option {
    margin: 10px 0;
    padding: 8px;
    cursor: pointer;
    border-radius: 4px;
}
.option:hover {
    background-color: #eee;
}
.option.selected {
    background-color: #3498db;
    color: white;
}
.option.multi-selected {
    background-color: #9b59b6;
    color: white;
}
.true-false-options {
    display: flex;
    gap: 20px;
}
.true-false-option {
    padding: 10px 20px;
    border: 1px solid #ddd;
    border-radius: 5px;
    cursor: pointer;
}
.true-false-option.selected {
    background-color: #3498db;
    color: white;
    border-color: #3498db;
}
.fill-blank-input {
    width: 100%;
    padding: 8px;
    margin-top: 10px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 16px;
}
.navigation {
    display: flex;
    justify-content: space-between;
    margin-top: 30px;
}
button {
    padding: 10px 20px;
    background-color: #3498db;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 16px;
}
button:hover {
    background-color: #2980b9;
}
button:disabled {
    background-color: #95a5a6;
    cursor: not-allowed;
}
.submit-btn {
    background-color: #2ecc71;
}
.submit-btn:hover {
    background-color: #27ae60;
}
.result {
    display: none;
    text-align: center;
    padding: 20px;
}
.score {
    font-size: 24px;
    font-weight: bold;
    color: #2ecc71;
}

答题卡样式

.answer-sheet h3 {
    margin-top: 0;
    padding-bottom: 10px;
    border-bottom: 1px solid #eee;
    text-align: center;
}
.answer-buttons {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 10px;
}
.answer-btn {
    width: 100%;
    aspect-ratio: 1;
    border: 1px solid #ddd;
    border-radius: 5px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-weight: bold;
    background-color: white;
}
.answer-btn:hover {
    background-color: #f0f0f0;
}
.answer-btn.current {
    border: 2px solid #3498db;
    color: #3498db;
}
.answer-btn.answered {
    background-color: #3498db;
    color: white;
    border-color: #3498db;
}
.answer-btn.unanswered {
    background-color: #f1f1f1;
    color: #999;
}

核心功能实现

定义基础数据
// 题型常量
const QUESTION_TYPES = {
    SINGLE_CHOICE: 'single-choice',
    MULTI_CHOICE: 'multi-choice',
    TRUE_FALSE: 'true-false',
    FILL_BLANK: 'fill-blank'
};

// 考试数据
const examData = {
    title: "JavaScript综合测试",
    timeLimit: 30 * 60, // 30分钟,以秒为单位
    questions: [
        {
            type: QUESTION_TYPES.SINGLE_CHOICE,
            question: "JavaScript是什么类型的语言?",
            options: ["编译型", "解释型", "混合型", "标记型"],
            answer: 1,
            score: 10
        },
        {
            type: QUESTION_TYPES.MULTI_CHOICE,
            question: "以下哪些是JavaScript的数据类型?(多选)",
            options: ["String", "Boolean", "Number", "Float", "Object"],
            answer: [0, 1, 2, 4],
            score: 15
        },
        // ...
    ]
};
生成答题卡
function createAnswerSheet() {
    answerButtonsContainer.innerHTML = '';

    examData.questions.forEach((_, index) => {
        const btn = document.createElement('button');
        btn.className = 'answer-btn unanswered';
        btn.textContent = index + 1;
        btn.onclick = () => jumpToQuestion(index);

        answerButtonsContainer.appendChild(btn);
    });
}
渲染不同题型
function showQuestion() {
    const question = examData.questions[currentQuestion];
    const typeLabel = getTypeLabel(question.type);

    let html = `<div class="question">
<h3>题目 ${currentQuestion + 1}/${examData.questions.length}: ${question.question}
<span class="question-type">${typeLabel}</span>
</h3>
<div class="options">`;

    // 根据题型生成不同的HTML
    switch(question.type) {
        case QUESTION_TYPES.SINGLE_CHOICE:
            html += generateSingleChoiceHTML(question);
            break;
        case QUESTION_TYPES.MULTI_CHOICE:
            html += generateMultiChoiceHTML(question);
            break;
        case QUESTION_TYPES.TRUE_FALSE:
            html += generateTrueFalseHTML(question);
            break;
        case QUESTION_TYPES.FILL_BLANK:
            html += generateFillBlankHTML(question);
            break;
    }

    html += `</div></div>`;
    subjectContainer.innerHTML = html;

    // 更新导航按钮状态
    prevBtn.disabled = currentQuestion === 0;
    nextBtn.disabled = currentQuestion === examData.questions.length - 1;

    // 更新答题卡
    updateAnswerSheet();
}
跳转到指定题目
function jumpToQuestion(index) {
    currentQuestion = index;
    showQuestion();
}
更新答题卡状态
function updateAnswerSheet() {
    const buttons = answerButtonsContainer.querySelectorAll('.answer-btn');

    buttons.forEach((btn, index) => {
        btn.classList.remove('current', 'answered', 'unanswered');

        if (index === currentQuestion) {
            btn.classList.add('current');
        }
        if (userAnswers[index] === null || userAnswers[index] === '' || (Array.isArray(userAnswers[index]) && userAnswers[index].length === 0) ) {
            btn.classList.add('unanswered');
        } else {
            btn.classList.add('answered');
        }
    });
}
监听做题事件
事件名事件
选择单选题选项selectSingleChoice
选择多选题选项toggleMultiChoice
选择判断题选项selectTrueFalse
更新填空题答案updateFillBlankAnswer
提交试卷
function submitExam() {
    clearInterval(timer);

    // 计算分数
    let score = 0;

    examData.questions.forEach((question, index) => {
        const userAnswer = userAnswers[index];
        let isCorrect = false;

        switch(question.type) {
            case QUESTION_TYPES.SINGLE_CHOICE:
                isCorrect = userAnswer === question.answer;
                break;
            case QUESTION_TYPES.MULTI_CHOICE:
                if (Array.isArray(userAnswer)) {
                    // 检查答案数组是否完全相同
                    const userSorted = [...userAnswer].sort();
                    const answerSorted = [...question.answer].sort();
                    isCorrect = JSON.stringify(userSorted) === JSON.stringify(answerSorted);
                }
                break;
            case QUESTION_TYPES.TRUE_FALSE:
                isCorrect = userAnswer === question.answer;
                break;
            case QUESTION_TYPES.FILL_BLANK:
                isCorrect = userAnswer && userAnswer.toString().toLowerCase() === question.answer.toLowerCase();
                break;
        }

        if (isCorrect) {
            score += question.score;
        }
    });

    // 显示结果
    document.getElementById('subject').style.display = 'none';
    document.querySelector('.navigation').style.display = 'none';
    resultDiv.style.display = 'block';
    finalScore.textContent = score;

    // 根据分数显示不同消息
    const totalScore = examData.questions.reduce((sum, q) => sum + q.score, 0);
    const percentage = (score / totalScore) * 100;

    if (percentage >= 80) {
        resultMessage.textContent = "优秀!你掌握了大部分知识点。";
    } else if (percentage >= 60) {
        resultMessage.textContent = "良好!继续努力,你可以做得更好。";
    } else if (percentage >= 40) {
        resultMessage.textContent = "及格!建议复习相关知识点。";
    } else {
        resultMessage.textContent = "不及格!需要加强学习。";
    }
}

扩展建议

  • 防切屏功能
  • 倒计时功能优化
  • 实现错题回顾功能
  • 添加用户登录与成绩保存功能
  • 集成后端进行数据持久化

完整代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>在线考试系统 - 多题型版</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            background-color: #f5f5f5;
        }
        .container {
            display: flex;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }
        .exam-container {
            flex: 3;
            background-color: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
            margin-right: 20px;
        }
        .answer-sheet {
            flex: 1;
            background-color: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
            height: fit-content;
            position: sticky;
            top: 20px;
        }

        .header {
            display: flex;
            justify-content: space-between;
            margin-bottom: 20px;
            padding-bottom: 10px;
            border-bottom: 1px solid #eee;
        }
        .timer {
            font-weight: bold;
            color: #e74c3c;
        }
        .question {
            margin-bottom: 20px;
            padding: 15px;
            background-color: #f9f9f9;
            border-radius: 5px;
        }
        .question h3 {
            margin-top: 0;
            color: #2c3e50;
        }
        .question-type {
            display: inline-block;
            padding: 2px 8px;
            background-color: #3498db;
            color: white;
            border-radius: 4px;
            font-size: 12px;
            margin-left: 10px;
        }
        .options {
            margin-left: 20px;
        }
        .option {
            margin: 10px 0;
            padding: 8px;
            cursor: pointer;
            border-radius: 4px;
        }
        .option:hover {
            background-color: #eee;
        }
        .option.selected {
            background-color: #3498db;
            color: white;
        }
        .option.multi-selected {
            background-color: #9b59b6;
            color: white;
        }
        .true-false-options {
            display: flex;
            gap: 20px;
        }
        .true-false-option {
            padding: 10px 20px;
            border: 1px solid #ddd;
            border-radius: 5px;
            cursor: pointer;
        }
        .true-false-option.selected {
            background-color: #3498db;
            color: white;
            border-color: #3498db;
        }
        .fill-blank-input {
            width: 100%;
            padding: 8px;
            margin-top: 10px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 16px;
        }
        .navigation {
            display: flex;
            justify-content: space-between;
            margin-top: 30px;
        }
        button {
            padding: 10px 20px;
            background-color: #3498db;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 16px;
        }
        button:hover {
            background-color: #2980b9;
        }
        button:disabled {
            background-color: #95a5a6;
            cursor: not-allowed;
        }
        .submit-btn {
            background-color: #2ecc71;
        }
        .submit-btn:hover {
            background-color: #27ae60;
        }
        .result {
            display: none;
            text-align: center;
            padding: 20px;
        }
        .score {
            font-size: 24px;
            font-weight: bold;
            color: #2ecc71;
        }

        .answer-sheet h3 {
            margin-top: 0;
            padding-bottom: 10px;
            border-bottom: 1px solid #eee;
            text-align: center;
        }
        .answer-buttons {
            display: grid;
            grid-template-columns: repeat(5, 1fr);
            gap: 10px;
        }
        .answer-btn {
            width: 100%;
            aspect-ratio: 1;
            border: 1px solid #ddd;
            border-radius: 5px;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            font-weight: bold;
            background-color: white;
        }
        .answer-btn:hover {
            background-color: #f0f0f0;
        }
        .answer-btn.current {
            border: 2px solid #3498db;
            color: #3498db;
        }
        .answer-btn.answered {
            background-color: #3498db;
            color: white;
            border-color: #3498db;
        }
        .answer-btn.unanswered {
            background-color: #f1f1f1;
            color: #999;
        }
    </style>
</head>
<body>
<div class="container">
    <!-- 考试内容 -->
    <div class="exam-container">
        <!-- 标题和计时器 -->
        <div class="header">
            <h2>在线考试系统</h2>
            <div class="timer">剩余时间: <span id="time">30:00</span></div>
        </div>

        <!-- 题目 -->
        <div id="subject"></div>

        <!-- 导航按钮 -->
        <div class="navigation">
            <button id="prev-btn" disabled>上一题</button>
            <button id="next-btn">下一题</button>
            <button id="submit-btn" class="submit-btn">提交试卷</button>
        </div>

        <!-- 结果 -->
        <div id="result" class="result">
            <h2>考试结束</h2>
            <p>你的得分是: <span class="score" id="final-score">0</span></p>
            <p id="result-message"></p>
        </div>
    </div>

    <!-- 答题卡 -->
    <div class="answer-sheet">
        <h3>答题卡</h3>
        <div class="answer-buttons" id="answer-buttons"></div>
    </div>
</div>

<script>
    // 题型常量
    const QUESTION_TYPES = {
        SINGLE_CHOICE: 'single-choice',
        MULTI_CHOICE: 'multi-choice',
        TRUE_FALSE: 'true-false',
        FILL_BLANK: 'fill-blank'
    };

    // 考试数据
    const examData = {
        title: "JavaScript综合测试",
        timeLimit: 30 * 60, // 30分钟,以秒为单位
        questions: [
            {
                type: QUESTION_TYPES.SINGLE_CHOICE,
                question: "JavaScript是什么类型的语言?",
                options: ["编译型", "解释型", "混合型", "标记型"],
                answer: 1,
                score: 10
            },
            {
                type: QUESTION_TYPES.MULTI_CHOICE,
                question: "以下哪些是JavaScript的数据类型?(多选)",
                options: ["String", "Boolean", "Number", "Float", "Object"],
                answer: [0, 1, 2, 4], // 多选的答案使用数组
                score: 15
            },
            {
                type: QUESTION_TYPES.TRUE_FALSE,
                question: "JavaScript和Java是同一种语言。",
                answer: false, // true或false
                score: 5
            },
            {
                type: QUESTION_TYPES.FILL_BLANK,
                question: "用于向数组末尾添加元素的方法是______。",
                answer: "push", // 填空题的答案
                score: 10
            },
            {
                type: QUESTION_TYPES.SINGLE_CHOICE,
                question: "哪个方法可以将字符串转换为整数?",
                options: ["parseInt()", "parseString()", "toInteger()", "stringToInt()"],
                answer: 0,
                score: 10
            },
            {
                type: QUESTION_TYPES.MULTI_CHOICE,
                question: "以下哪些是JavaScript的循环语句?(多选)",
                options: ["for", "while", "do...while", "repeat", "loop"],
                answer: [0, 1, 2],
                score: 15
            },
            {
                type: QUESTION_TYPES.TRUE_FALSE,
                question: "JavaScript中可以使用let和const声明变量。",
                answer: true,
                score: 5
            },
            {
                type: QUESTION_TYPES.FILL_BLANK,
                question: "用于检测变量类型的操作符是______。",
                answer: "typeof",
                score: 10
            }
        ]
    };

    // 全局变量
    let currentQuestion = 0;
    let userAnswers = Array(examData.questions.length).fill(null);
    let timeLeft = examData.timeLimit;
    let timer;

    // DOM元素
    const subjectContainer = document.getElementById('subject');
    const prevBtn = document.getElementById('prev-btn');
    const nextBtn = document.getElementById('next-btn');
    const submitBtn = document.getElementById('submit-btn');
    const timeDisplay = document.getElementById('time');
    const resultDiv = document.getElementById('result');
    const finalScore = document.getElementById('final-score');
    const resultMessage = document.getElementById('result-message');
    const answerButtonsContainer = document.getElementById('answer-buttons');

    // 初始化考试
    function initExam() {
        createAnswerSheet();
        showQuestion();
        startTimer();
    }

    // 创建答题卡
    function createAnswerSheet() {
        answerButtonsContainer.innerHTML = '';

        examData.questions.forEach((_, index) => {
            const btn = document.createElement('button');
            btn.className = 'answer-btn unanswered';
            btn.textContent = index + 1;
            btn.onclick = () => jumpToQuestion(index);

            answerButtonsContainer.appendChild(btn);
        });
    }

    // 更新答题卡状态
    function updateAnswerSheet() {
        const buttons = answerButtonsContainer.querySelectorAll('.answer-btn');

        buttons.forEach((btn, index) => {
            btn.classList.remove('current', 'answered', 'unanswered');

            if (index === currentQuestion) {
                btn.classList.add('current');
            }
            if (userAnswers[index] === null || userAnswers[index] === '' || (Array.isArray(userAnswers[index]) && userAnswers[index].length === 0) ) {
                btn.classList.add('unanswered');
            } else {
                btn.classList.add('answered');
            }
        });
    }

    // 跳转到指定题目
    function jumpToQuestion(index) {
        currentQuestion = index;
        showQuestion();
    }

    // 显示当前题目
    function showQuestion() {
        const question = examData.questions[currentQuestion];
        const typeLabel = getTypeLabel(question.type);

        let html = `<div class="question">
                    <h3>题目 ${currentQuestion + 1}/${examData.questions.length}: ${question.question}
                        <span class="question-type">${typeLabel}</span>
                    </h3>
                    <div class="options">`;

        // 根据题型生成不同的HTML
        switch(question.type) {
            case QUESTION_TYPES.SINGLE_CHOICE:
                html += generateSingleChoiceHTML(question);
                break;
            case QUESTION_TYPES.MULTI_CHOICE:
                html += generateMultiChoiceHTML(question);
                break;
            case QUESTION_TYPES.TRUE_FALSE:
                html += generateTrueFalseHTML(question);
                break;
            case QUESTION_TYPES.FILL_BLANK:
                html += generateFillBlankHTML(question);
                break;
        }

        html += `</div></div>`;
        subjectContainer.innerHTML = html;

        // 更新导航按钮状态
        prevBtn.disabled = currentQuestion === 0;
        nextBtn.disabled = currentQuestion === examData.questions.length - 1;

        // 更新答题卡
        updateAnswerSheet();
    }

    // 获取题型标签
    function getTypeLabel(type) {
        switch(type) {
            case QUESTION_TYPES.SINGLE_CHOICE: return '单选题';
            case QUESTION_TYPES.MULTI_CHOICE: return '多选题';
            case QUESTION_TYPES.TRUE_FALSE: return '判断题';
            case QUESTION_TYPES.FILL_BLANK: return '填空题';
            default: return '';
        }
    }

    // 生成单选题
    function generateSingleChoiceHTML(question) {
        let html = '';
        question.options.forEach((option, index) => {
            const isSelected = userAnswers[currentQuestion] === index;
            html += `<div class="option ${isSelected ? 'selected' : ''}" onclick="selectSingleChoice(${index})">
                        ${String.fromCharCode(65 + index)}. ${option}
                    </div>`;
        });
        return html;
    }

    // 生成多选题
    function generateMultiChoiceHTML(question) {
        let html = '';
        question.options.forEach((option, index) => {
            const isSelected = Array.isArray(userAnswers[currentQuestion]) && userAnswers[currentQuestion].includes(index);
            html += `<div class="option ${isSelected ? 'multi-selected' : ''}" onclick="toggleMultiChoice(${index})">
                        ${String.fromCharCode(65 + index)}. ${option}
                    </div>`;
        });
        return html;
    }

    // 生成判断题
    function generateTrueFalseHTML(question) {
        const userAnswer = userAnswers[currentQuestion];
        return `<div class="true-false-options">
                    <div class="true-false-option ${userAnswer === true ? 'selected' : ''}"
                         onclick="selectTrueFalse(true)">正确</div>
                    <div class="true-false-option ${userAnswer === false ? 'selected' : ''}"
                         onclick="selectTrueFalse(false)">错误</div>
                </div>`;
    }

    // 生成填空题
    function generateFillBlankHTML(question) {
        const userAnswer = userAnswers[currentQuestion] || '';
        return `<input type="text" class="fill-blank-input"
                       value="${userAnswer}"
                       oninput="updateFillBlankAnswer(this.value)"
                       placeholder="请输入答案">`;
    }

    // 选择单选题选项
    function selectSingleChoice(optionIndex) {
        userAnswers[currentQuestion] = optionIndex;
        showQuestion();
    }

    // 选择多选题选项
    function toggleMultiChoice(optionIndex) {
        if (!Array.isArray(userAnswers[currentQuestion])) {
            userAnswers[currentQuestion] = [];
        }

        const index = userAnswers[currentQuestion].indexOf(optionIndex);
        if (index === -1) {
            userAnswers[currentQuestion].push(optionIndex);
        } else {
            userAnswers[currentQuestion].splice(index, 1);
        }

        showQuestion();
    }

    // 选择判断题选项
    function selectTrueFalse(answer) {
        userAnswers[currentQuestion] = answer;
        showQuestion();
    }

    // 更新填空题答案
    function updateFillBlankAnswer(answer) {
        userAnswers[currentQuestion] = answer.trim();
        updateAnswerSheet();
    }

    // 上一题
    function prevQuestion() {
        if (currentQuestion > 0) {
            currentQuestion--;
            showQuestion();
        }
    }

    // 下一题
    function nextQuestion() {
        if (currentQuestion < examData.questions.length - 1) {
            currentQuestion++;
            showQuestion();
        }
    }

    // 开始计时器
    function startTimer() {
        updateTimerDisplay();
        timer = setInterval(() => {
            timeLeft--;
            updateTimerDisplay();

            if (timeLeft <= 0) {
                clearInterval(timer);
                submitExam();
            }
        }, 1000);
    }

    // 更新计时器显示
    function updateTimerDisplay() {
        const minutes = Math.floor(timeLeft / 60);
        const seconds = timeLeft % 60;
        timeDisplay.textContent = `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
    }

    // 提交试卷
    function submitExam() {
        clearInterval(timer);

        // 计算分数
        let score = 0;

        examData.questions.forEach((question, index) => {
            const userAnswer = userAnswers[index];
            let isCorrect = false;

            switch(question.type) {
                case QUESTION_TYPES.SINGLE_CHOICE:
                    isCorrect = userAnswer === question.answer;
                    break;
                case QUESTION_TYPES.MULTI_CHOICE:
                    if (Array.isArray(userAnswer)) {
                        // 检查答案数组是否完全相同
                        const userSorted = [...userAnswer].sort();
                        const answerSorted = [...question.answer].sort();
                        isCorrect = JSON.stringify(userSorted) === JSON.stringify(answerSorted);
                    }
                    break;
                case QUESTION_TYPES.TRUE_FALSE:
                    isCorrect = userAnswer === question.answer;
                    break;
                case QUESTION_TYPES.FILL_BLANK:
                    isCorrect = userAnswer && userAnswer.toString().toLowerCase() === question.answer.toLowerCase();
                    break;
            }

            if (isCorrect) {
                score += question.score;
            }
        });

        // 显示结果
        document.getElementById('subject').style.display = 'none';
        document.querySelector('.navigation').style.display = 'none';
        resultDiv.style.display = 'block';
        finalScore.textContent = score;

        // 根据分数显示不同消息
        const totalScore = examData.questions.reduce((sum, q) => sum + q.score, 0);
        const percentage = (score / totalScore) * 100;

        if (percentage >= 80) {
            resultMessage.textContent = "优秀!你掌握了大部分知识点。";
        } else if (percentage >= 60) {
            resultMessage.textContent = "良好!继续努力,你可以做得更好。";
        } else if (percentage >= 40) {
            resultMessage.textContent = "及格!建议复习相关知识点。";
        } else {
            resultMessage.textContent = "不及格!需要加强学习。";
        }
    }

    // 事件监听
    prevBtn.addEventListener('click', prevQuestion);
    nextBtn.addEventListener('click', nextQuestion);
    submitBtn.addEventListener('click', () => {
        if (confirm("确定要提交试卷吗?提交后将无法修改答案。")) {
            submitExam();
        }
    });

    // 开始考试
    initExam();
</script>
</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2395259.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

谷歌工作自动化——仙盟大衍灵机——仙盟创梦IDE

下载地址 https://chromewebstore.google.com/detail/selenium-ide/mooikfkahbdckldjjndioackbalphokd https://chrome.zzzmh.cn/info/mooikfkahbdckldjjndioackbalphokd

秒杀系统—1.架构设计和方案简介

大纲 1.秒杀系统的方案设计要点 2.秒杀系统的数据 页面 接口的处理方案 3.秒杀系统的负载均衡方案底层相关 4.秒杀系统的限流机制和超卖问题处理 5.秒杀系统的异步下单和高可用方案 1.秒杀系统的方案设计要点 (1)秒杀促销活动的数据处理 (2)秒杀促销活动的页面处理 (…

基于FashionMnist数据集的自监督学习(生成式自监督学习AE算法)

目录 一&#xff0c;生成式自监督学习 1.1 简介 1.2 核心思想 1.3 常见算法 1.3.1 自动编码器&#xff08;Autoencoder&#xff09; 1.3.2 生成对抗网络&#xff08;GANs&#xff09; 1.3.3 变分自编码器&#xff08;VAE&#xff09; 1.3.4 Transformer-based 模型&…

从监控到告警:Prometheus+Grafana+Alertmanager+告警通知服务全链路落地实践

文章目录 一、引言1.1 监控告警的必要性1.2 监控告警的基本原理1.2.1 指标采集与存储1.2.2 告警规则与触发机制1.2.3 多渠道通知与闭环 二、技术选型与架构设计2.1 为什么选择 Prometheus 及其生态2.1.1 Prometheus 优势分析2.1.2 Grafana 可视化能力2.1.3 Alertmanager 灵活告…

WPF【09】WPF基础入门 (三层架构与MVC架构)

9-2 【操作】WPF 基础入门 新建一项目 Create a new project - WPF Application (A project for creating a .NET Core WPF Application) - Next - .NET 5.0 (Current) - Create 项目创建完成&#xff0c;VS自动打开 GUI用户界面&#xff0c;格式是 .xaml文件&#xff0c;跟xm…

macOS 风格番茄计时器:设计与实现详解

macOS 风格番茄计时器&#xff1a;设计与实现详解 概述 本文介绍一款采用 macOS 设计语言的网页版番茄计时器实现。该计时器完全遵循苹果的人机界面指南(HIG)&#xff0c;提供原汁原味的 macOS 使用体验&#xff0c;同时具备响应式设计和深色模式支持。 核心特性 原生 macOS…

oracle goldengate实现远程抽取postgresql 到 postgresql的实时同步【绝对无坑版,亲测流程验证】

oracle goldengate实现postgresql 到 postgresql的实时同步 源端&#xff1a;postgresql1 -> postgresql2 流复制主备同步 目标端&#xff1a;postgresql 数据库版本&#xff1a;postgresql 12.14 ogg版本&#xff1a;21.3 架构图&#xff1a; 数据库安装以及流复制主备…

ISCC-2025-web-wp

web 校赛 校赛靠着ENOCH师傅发力&#xff0c;也是一路躺进了区域赛&#xff0c;E师傅不好意思发这抽象比赛的wp(这比赛确实啥必到让人大开眼界&#xff0c;反正明年我是肯定不会打了)&#xff0c;我就顺手要过来连着区域赛的一起发了 web 150分 按照提示进入/includes/fla…

King3399(ubuntu文件系统)iic(i2c)功能测试

0 引言 前面两篇博文简要介绍了板子上uart部分的内容&#xff0c;但在驱动开发时&#xff0c;我们遇到的外设更多的是以i2c或spi进行通信&#xff0c;本文将对king3399的i2c进行测试并对硬件电路、设备树与驱动程序进行分析 如果使用的i2c设备不是mma8452&#xff0c;建议先看…

德思特新闻 | 德思特与es:saar正式建立合作伙伴关系

德思特新闻 2025年5月9日&#xff0c;德思特科技有限公司&#xff08;以下简称“德思特”&#xff09;与德国嵌入式系统专家es:saar GmbH正式达成合作伙伴关系。此次合作旨在将 es:saar 的先进嵌入式开发与测试工具引入中国及亚太市场&#xff0c;助力本地客户提升产品开发效率…

基于原生JavaScript前端和 Flask 后端的Todo 应用

Demo地址&#xff1a;https://gitcode.com/rmbnetlife/todo-app-js-flask.git Python Todo 应用 这是一个使用Python Flask框架开发的简单待办事项(Todo)应用&#xff0c;采用前后端分离架构。本项目实现了待办事项的添加、删除、状态切换等基本功能&#xff0c;并提供了直观…

MIT 6.S081 2020 Lab6 Copy-on-Write Fork for xv6 个人全流程

文章目录 零、写在前面一、Implement copy-on write1.1 说明1.2 实现1.2.1 延迟复制与释放1.2.2 写时复制 零、写在前面 可以阅读下 《xv6 book》 的第五章中断和设备驱动。 问题 在 xv6 中&#xff0c;fork() 系统调用会将父进程的整个用户空间内存复制到子进程中。**如果父…

第304个Vulnhub靶场演练攻略:digital world.local:FALL

digital world.local&#xff1a;FALL Vulnhub 演练 FALL (digitalworld.local: FALL) 是 Donavan 为 Vulnhub 打造的一款中型机器。这款实验室非常适合经验丰富的 CTF 玩家&#xff0c;他们希望在这类环境中检验自己的技能。那么&#xff0c;让我们开始吧&#xff0c;看看如何…

Unity 模拟高度尺系统开发详解——实现拖动、范围限制、碰撞吸附与本地坐标轴选择

内容将会持续更新&#xff0c;有错误的地方欢迎指正&#xff0c;谢谢! Unity 模拟高度尺系统开发详解——实现拖动、范围限制、碰撞吸附与本地坐标轴选择 TechX 坚持将创新的科技带给世界&#xff01; 拥有更好的学习体验 —— 不断努力&#xff0c;不断进步&#xff0c;不…

万字详解RTR RTSP SDP RTCP

目录 1 RTSP1.1 RTSP基本简介1.2 RSTP架构1.3 重点内容分析 2 RTR2.1 RTR简介2.2 RTP 封装 H.2642.3 RTP 解封装 H.2642.4 RTP封装 AAC2.5 RTP解封装AAC 3 SDP3.1 基础概念3.2 SDP协议示例解析3.3 重点知识 4 RTCP4.1 RTCP基础概念4.2 重点 5 总结 1 RTSP 1.1 RTSP基本简介 一…

云服务器如何自动更新系统并保持安全?

云服务器自动更新系统是保障安全、修补漏洞的重要措施。下面是常见 Linux 系统&#xff08;如 Ubuntu、Debian、CentOS&#xff09;和 Windows 服务器自动更新的做法和建议&#xff1a; 1. Linux 云服务器自动更新及安全维护 Ubuntu / Debian 系统 手动更新命令 sudo apt up…

[paddle]paddle2onnx无法转换Paddle3.0.0的json格式paddle inference模型

使用PDX 3.0rc1 训练时序缺陷检测后导出的模型无法转换 Informations (please complete the following information): Inference engine for deployment: PD INFERENCE 3.0-->onnxruntime Why convert to onnx&#xff1a;在端侧设备上部署 Paddle2ONNX Version: 1.3.1 解…

React项目在ios和安卓端要做一个渐变色背景,用css不支持,可使用react-native-linear-gradient

以上有个模块是灰色逐渐到白的背景色过渡 如果是css&#xff0c;以下代码就直接搞定 background: linear-gradient(180deg, #F6F6F6 0%, #FFF 100%);但是在RN中不支持这种写法&#xff0c;那应该写呢&#xff1f; 1.引入react-native-linear-gradient插件&#xff0c;我使用的是…

【数据分析】特征工程-特征选择

【数据分析】特征工程-特征选择 &#xff08;一&#xff09;方差过滤法1.1 消除方差为0的特征1.2 保留一半的特征1.3 特征是二分类时 &#xff08;二&#xff09;相关性过滤法2.1 卡方过滤2.2 F检验2.3 互信息法 &#xff08;三&#xff09;其他3.1 包装法3.2 嵌入法3.3 衍生特…

uni-app 安卓消失的字符去哪里了?maxLength失效了!

前情提要 皮一下~这个标题我还蛮喜欢的嘿嘿嘿【附上一个自行思考的猥琐的笑容】 前段时间不是在开发uni-app的一个小应用嘛,然后今天测试发现,有一个地方在苹果是没有问题的,但是在安卓上出现了问题,附上安卓的截图 在这里我是有限制maxLength=50的,而且,赋值字符串到字…