You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为随机抽题测验应用实现单选按钮、文本输入答题模式

Web测验应用剩余功能实现方案

改造题库结构

首先给现有题库的每道题增加type字段标记题型,支持三类取值:

  • radio:单选按钮题
  • select:下拉选择题(你已经实现的类型)
  • input:文本输入题

文本输入题不需要设置a/b/c/d选项,直接存储标准答案即可,改造后的题库示例:

const quizQuestions = [
    {
        type: "radio",
        question: "Which language runs in a web browser ?",
        a: "Python",
        b: "Javascript",
        c: "Java",
        d: "Flutter",
        ans: "b", 
    },
    {
        type: "select",
        question: "How many standard color names does HTML supports ?",
        a: "20",
        b: "90",
        c: "140",
        d: "125",
        ans: "c", 
    },
    {
        type: "radio",
        question: "Javascript displays numbers as base ?",
        a: "10",
        b: "2",
        c: "5",
        d: "12",
        ans: "a", 
    },
    {
        type: "radio",
        question: "Who is the father of computer ?",
        a: "Charles Babbage",
        b: "Allan Turing",
        c: "Issac Newton",
        d: "Bill Gate",
        ans: "a", 
    },
    {
        type: "radio",
        question: "The brain of a computer is ?",
        a: "ALU",
        b: "DVD",
        c: "CPU",
        d: "Memory",
        ans: "c", 
    },
    {
        type: "select",
        question: "What year was JavaScript launched ?",
        a: "1996",
        b: "1995",
        c: "1994",
        d: "1993",
        ans: "b", 
    },
    {
        type: "select",
        question: "Junk e-mail is called ?",
        a: "junk",
        b: "spoof",
        c: "sperm",
        d: "spam",
        ans: "d", 
    },
    {
        type: "radio",
        question: "Which tag is used for list-items ?",
        a: "<ol>",
        b: "<ul>",
        c: "<dl>",
        d: "<li>",
        ans: "d", 
    },
    {
        type: "select",
        question: "How old is Bill Gate ?",
        a: "59",
        b: "60",
        c: "56",
        d: "66",
        ans: "d", 
    },
    // 新增文本输入类题目,补足题型
    {
        type: "input",
        question: "What is the abbreviation of HyperText Markup Language?",
        ans: "HTML"
    },
    {
        type: "input",
        question: "Calculate the result of 8 * 7?",
        ans: "56"
    }
];

实现符合规则的随机抽题逻辑

抽题规则要求5道题至少覆盖1道单选、1道下拉、1道文本输入,实现逻辑为:先从三类题型中各抽1道保底,再从剩余题库中随机抽2道,最后打乱题目顺序避免题型固定排布,代码如下:

function pickRandomQuestions() {
    // 按题型分组
    const radioPool = quizQuestions.filter(q => q.type === "radio");
    const selectPool = quizQuestions.filter(q => q.type === "select");
    const inputPool = quizQuestions.filter(q => q.type === "input");

    // 三类题各抽1道保底
    const picked = [
        radioPool[Math.floor(Math.random() * radioPool.length)],
        selectPool[Math.floor(Math.random() * selectPool.length)],
        inputPool[Math.floor(Math.random() * inputPool.length)]
    ];

    // 抽剩余2道题,排除已选题目避免重复
    const restPool = quizQuestions.filter(q => !picked.includes(q));
    for (let i = 0; i < 2; i++) {
        const randomIndex = Math.floor(Math.random() * restPool.length);
        picked.push(restPool.splice(randomIndex, 1)[0]);
    }

    // 打乱题目顺序
    return picked.sort(() => Math.random() - 0.5);
}

// 初始化本次答题的题目列表、当前题号、用户答案存储
const currentQuizList = pickRandomQuestions();
let currentIndex = 0;
const userAnswers = new Array(5).fill(null);

动态渲染三类答题控件

删掉HTML中写死的下拉选择结构,把选项容器改成空容器,方便动态渲染不同题型:

<div class="question-options" id="optionsContainer">
  <!-- 题型控件动态生成 -->
</div>

编写题目渲染函数,根据当前题目的type字段生成对应答题控件,同时支持答案回填:

const questionTextEl = document.getElementById("question");
const questionNoEl = document.querySelector(".question-no h3");
const optionsContainer = document.getElementById("optionsContainer");

function renderQuestion() {
    const currentQ = currentQuizList[currentIndex];
    // 更新题号、题干
    questionNoEl.textContent = `Question ${currentIndex + 1} of 5`;
    questionTextEl.textContent = currentQ.question;
    // 清空上一题的控件
    optionsContainer.innerHTML = "";

    // 渲染单选按钮题
    if (currentQ.type === "radio") {
        ["a", "b", "c", "d"].forEach(optKey => {
            const label = document.createElement("label");
            label.style.color = "#fff";
            label.style.display = "flex";
            label.style.alignItems = "center";
            label.style.gap = "10px";
            label.style.cursor = "pointer";

            const radio = document.createElement("input");
            radio.type = "radio";
            radio.name = "answer";
            radio.value = optKey;
            // 回填已选答案
            if (userAnswers[currentIndex] === optKey) radio.checked = true;
            // 监听选择事件存答案
            radio.addEventListener("change", () => {
                userAnswers[currentIndex] = optKey;
            });

            label.append(radio, document.createTextNode(currentQ[optKey]));
            optionsContainer.appendChild(label);
        });
    }

    // 渲染下拉选择题(原有逻辑)
    if (currentQ.type === "select") {
        const select = document.createElement("select");
        select.innerHTML = `<option selected disabled>Choose your answer</option>`;
        ["a", "b", "c", "d"].forEach(optKey => {
            const opt = document.createElement("option");
            opt.value = optKey;
            opt.textContent = currentQ[optKey];
            if (userAnswers[currentIndex] === optKey) opt.selected = true;
            select.appendChild(opt);
        });
        select.addEventListener("change", e => {
            userAnswers[currentIndex] = e.target.value;
        });
        optionsContainer.appendChild(select);
    }

    // 渲染文本输入题
    if (currentQ.type === "input") {
        const input = document.createElement("input");
        input.type = "text";
        input.placeholder = "Type your answer here";
        input.style.padding = "8px";
        input.style.border = "none";
        input.style.outline = "none";
        input.style.fontSize = "15px";
        input.style.borderRadius = "4px";
        // 回填已输入内容
        if (userAnswers[currentIndex]) input.value = userAnswers[currentIndex];
        // 监听输入存答案,自动去首尾空格、转小写,降低判分误差
        input.addEventListener("input", e => {
            userAnswers[currentIndex] = e.target.value.trim().toLowerCase();
        });
        optionsContainer.appendChild(input);
    }
}

// 初始化渲染第一题
renderQuestion();

补全题目切换与判分逻辑

给上下题按钮绑定事件,支持切换题目、最后一题提交判分:

const prevBtn = document.querySelector(".prev");
const nextBtn = document.querySelector(".next");

prevBtn.addEventListener("click", () => {
    if (currentIndex > 0) {
        currentIndex--;
        renderQuestion();
    }
});

nextBtn.addEventListener("click", () => {
    if (currentIndex < 4) {
        currentIndex++;
        renderQuestion();
    } else {
        // 计算得分
        let score = 0;
        currentQuizList.forEach((q, idx) => {
            const correctAns = q.type === "input" ? q.ans.trim().toLowerCase() : q.ans;
            if (userAnswers[idx] === correctAns) score++;
        });
        alert(`Quiz finished! Your score is ${score}/5`);
    }
});

补充适配样式

在原有CSS中新增控件样式,保持视觉统一:

.question-options input[type="radio"] {
    width: 18px;
    height: 18px;
    cursor: pointer;
}

内容的提问来源于stack exchange,提问作者Abdulhameed Mustapha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 06:18:24