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

如何实现带三种答题模式的随机抽题测验应用

随机抽题测验应用实现方案

核心实现逻辑

  • 题库按单选(radio)、下拉选择(dropdown)、文本输入(text)三类分别存储,方便按规则抽题
  • 抽题时先从三类题型中各抽取1道保底,确保满足题型覆盖要求,剩余2道题从全题库随机抽取且不重复,最终打乱题目顺序
  • 动态根据题型渲染对应交互组件,支持上下题切换、答案实时暂存,最后一题自动切换为提交按钮计算得分
  • 完全适配你已完成的页面结构与样式,不需要修改现有CSS和HTML主体代码,仅需引入JS文件即可运行

使用说明

将下方JS代码保存为script.js,和你现有的HTML、CSS文件放在同一目录,在HTML文件的</body>闭合标签前添加以下代码引入JS:

<script src="script.js"></script>

完整JS代码

// 预设题库,可自行扩充题目内容
const questionBank = {
  radio: [
    {
      id: 1,
      question: "以下哪个是JavaScript的原始数据类型?",
      options: ["Object", "Array", "String", "Function"],
      answer: "String"
    },
    {
      id: 2,
      question: "CSS中哪个属性用于设置元素的外边距?",
      options: ["padding", "margin", "border", "outline"],
      answer: "margin"
    }
  ],
  dropdown: [
    {
      id: 3,
      question: "HTML中用于定义无序列表的标签是?",
      options: ["<ol>", "<ul>", "<li>", "<dl>"],
      answer: "<ul>"
    },
    {
      id: 4,
      question: "以下哪个方法可以向数组末尾添加元素?",
      options: ["shift()", "unshift()", "pop()", "push()"],
      answer: "push()"
    }
  ],
  text: [
    {
      id: 5,
      question: "请写出CSS中设置flex布局主轴方向为横向的属性值:flex-direction: ____;",
      answer: "row"
    },
    {
      id: 6,
      question: "JS中用于声明不可重新赋值的常量的关键字是?",
      answer: "const"
    }
  ]
}

// 全局状态管理
let selectedQuestions = []
let currentIndex = 0
let userAnswers = {}

// 按规则抽取5道不重复、覆盖三类题型的题目
function getRandomQuestions() {
  const result = []
  // 三类题型各抽1道保底
  result.push(questionBank.radio[Math.floor(Math.random() * questionBank.radio.length)])
  result.push(questionBank.dropdown[Math.floor(Math.random() * questionBank.dropdown.length)])
  result.push(questionBank.text[Math.floor(Math.random() * questionBank.text.length)])
  
  // 合并全量题库,抽取剩余2道题,做去重处理
  const allQuestions = [...questionBank.radio, ...questionBank.dropdown, ...questionBank.text]
  while (result.length < 5) {
    const randomQ = allQuestions[Math.floor(Math.random() * allQuestions.length)]
    if (!result.find(q => q.id === randomQ.id)) {
      result.push(randomQ)
    }
  }
  // 打乱题目顺序
  return result.sort(() => Math.random() - 0.5)
}

// 渲染当前索引对应的题目
function renderCurrentQuestion() {
  const quizContainer = document.querySelector('.quiz')
  const currentQ = selectedQuestions[currentIndex]
  
  // 识别当前题目题型
  let questionType = 'radio'
  if (questionBank.dropdown.find(q => q.id === currentQ.id)) questionType = 'dropdown'
  if (questionBank.text.find(q => q.id === currentQ.id)) questionType = 'text'

  // 基础题目结构
  let questionHtml = `<div class="question-item" style="color: #fff; margin: 40px 0;">
    <p style="font-size: 22px; margin-bottom: 25px;">${currentIndex + 1}. ${currentQ.question}</p>
  `

  // 按题型渲染对应交互组件
  if (questionType === 'radio') {
    currentQ.options.forEach(option => {
      const checked = userAnswers[currentQ.id] === option ? 'checked' : ''
      questionHtml += `<label style="display: block; margin: 12px 0; font-size: 18px; cursor: pointer;">
        <input type="radio" name="q${currentQ.id}" value="${option}" ${checked} style="margin-right: 10px; transform: scale(1.2);">
        ${option}
      </label>`
    })
  } else if (questionType === 'dropdown') {
    const savedValue = userAnswers[currentQ.id] || ''
    questionHtml += `<select name="q${currentQ.id}" style="padding: 10px 20px; width: 300px; font-size: 16px; border-radius: 5px; border: none;">
      <option value="">请选择答案</option>
      ${currentQ.options.map(opt => `<option value="${opt}" ${savedValue === opt ? 'selected' : ''}>${opt}</option>`).join('')}
    </select>`
  } else if (questionType === 'text') {
    const savedValue = userAnswers[currentQ.id] || ''
    questionHtml += `<input type="text" name="q${currentQ.id}" value="${savedValue}" placeholder="请输入你的答案" style="padding: 10px 20px; width: 300px; font-size: 16px; border-radius: 5px; border: none;">`
  }

  questionHtml += `</div>`
  quizContainer.innerHTML = questionHtml

  // 绑定答案实时保存事件
  bindAnswerSaveEvent(currentQ.id, questionType)
  // 更新切换按钮状态
  updateToggleButtonStatus()
}

// 绑定答案输入/选择的实时保存逻辑
function bindAnswerSaveEvent(questionId, questionType) {
  if (questionType === 'radio') {
    const radioList = document.querySelectorAll(`input[name="q${questionId}"]`)
    radioList.forEach(radio => {
      radio.addEventListener('change', e => {
        userAnswers[questionId] = e.target.value
      })
    })
  } else if (questionType === 'dropdown') {
    const select = document.querySelector(`select[name="q${questionId}"]`)
    select.addEventListener('change', e => {
      userAnswers[questionId] = e.target.value
    })
  } else if (questionType === 'text') {
    const input = document.querySelector(`input[name="q${questionId}"]`)
    input.addEventListener('input', e => {
      userAnswers[questionId] = e.target.value.trim()
    })
  }
}

// 更新上下题/提交按钮的可用状态
function updateToggleButtonStatus() {
  const prevBtn = document.querySelector('.prev')
  const nextBtn = document.querySelector('.next')
  
  // 第一题禁用上一题按钮
  prevBtn.disabled = currentIndex === 0
  prevBtn.style.opacity = currentIndex === 0 ? '0.5' : '1'

  // 最后一题将下一题按钮改为提交
  if (currentIndex === selectedQuestions.length - 1) {
    nextBtn.querySelector('span').textContent = '提交'
    nextBtn.querySelector('i').className = 'bx bx-check'
  } else {
    nextBtn.querySelector('span').textContent = 'Next'
    nextBtn.querySelector('i').className = 'bx bx-right-arrow-alt'
  }
}

// 计算答题得分
function calculateFinalScore() {
  let correctCount = 0
  selectedQuestions.forEach(question => {
    // 文本答案不区分大小写匹配
    if (userAnswers[question.id]?.toLowerCase() === question.answer.toLowerCase()) {
      correctCount++
    }
  })
  alert(`答题完成!你的得分是:${correctCount}/5`)
  // 重置测验
  initQuiz()
}

// 初始化测验
function initQuiz() {
  selectedQuestions = getRandomQuestions()
  currentIndex = 0
  userAnswers = {}
  renderCurrentQuestion()
}

// 绑定切换按钮事件
document.querySelector('.prev').addEventListener('click', () => {
  if (currentIndex > 0) {
    currentIndex--
    renderCurrentQuestion()
  }
})

document.querySelector('.next').addEventListener('click', () => {
  if (currentIndex === selectedQuestions.length - 1) {
    calculateFinalScore()
    return
  }
  currentIndex++
  renderCurrentQuestion()
})

// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', initQuiz)

你可以直接修改questionBank里的题目内容、新增题目,代码会自动适配抽题逻辑,不需要修改其他核心逻辑。


内容的提问来源于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.28 05:57:14