用纯HTML+CSS+JS实现H5测试题页面:动态渲染题目、data-*绑定题干选项、userAnswers对象存答案、localStorage持久化进度、单选name统一、跳过/返回时同步DOM与数据、提交后清空存储并展示解析,防touch延迟冲突。

怎么用纯 HTML + CSS + JavaScript 实现一个可运行的 H5 测试题页面
不需要框架,不依赖后端,一个 index.html 文件就能跑起来——关键在结构清晰、状态可控、交互不卡顿。
核心是把“题干—选项—提交—反馈”这四个环节串成可维护的流程,而不是堆 div 和 onclick。常见错误是直接写死所有题目 DOM,导致加题/改分/跳题都得重写 HTML;或者用全局变量存答案,一刷新就丢数据。
- 题干和选项用
data-*属性绑定题号和选项值,比如data-question-id="2"、data-option-value="B" - 用单个
<section id="question-area">容器动态渲染每道题,避免 DOM 膨胀 - 用户选择后先存在 JS 对象里(如
userAnswers = {1: "A", 2: "C"}),提交时再统一校验 - 禁用重复点击:选完立刻给当前题的所有
input[type="radio"]加disabled,防止手滑多点
为什么 localStorage 比 sessionStorage 更适合 H5 测试题保存进度
用户中途退出再回来,得接着答——这是 H5 测试题的基本体验底线。用 sessionStorage 的话,关掉标签页就清空,等于白做;而 localStorage 能跨会话保留,但要注意清理时机。
- 每次选答案就调用
localStorage.setItem("quiz_answers", JSON.stringify(userAnswers)) - 页面加载时检查
localStorage.getItem("quiz_answers"),有则还原状态并高亮已选项 - 提交成功后必须手动清除:
localStorage.removeItem("quiz_answers"),否则下次打开还是上次未交卷的状态 - 别用
localStorage存原始 HTML 字符串或函数,只存结构化数据(对象/数组)
如何让单选题支持「跳过」和「返回修改」而不乱状态
用户不是机器,需要回看、反悔、跳着答。难点在于 DOM 状态、JS 数据、本地存储三者同步,稍一错位就会出现“明明选了 C 却显示未作答”这类问题。
立即学习“前端免费学习笔记(深入)”;
- 每个单选组用唯一
name(如name="q3"),确保浏览器原生单选逻辑生效 - 点击「下一题」前,先检查当前题是否已选:没选就自动记录
userAnswers[currentQ] = null,表示跳过 - 「上一题」按钮不销毁 DOM,只切换
display: none,并从userAnswers中取值回填:document.querySelector('input[value="' + userAnswers[prevQ] + '"]').checked = true - 如果某题被跳过,回到它时要主动移除所有
disabled,否则无法补选
提交后怎么算分并显示逐题解析,又不让用户刷页面重试
分数不能靠前端算完就信,但解析可以即时给。重点是防刷新重试——不是靠技术锁死(那没用),而是让重试成本明显高于收益。
- 提交后立即禁用所有题干区域:
document.getElementById("question-area").innerHTML = "...",并清空localStorage - 解析页用 JS 动态生成,每道题下方放
<div class="explanation">...,内容来自预置的explanations = {"1": "因为...", "2": "注意..."} - 不要在解析页放「再测一次」按钮;真要支持重测,就用「重新开始」链接跳转到新页面(带时间戳参数,如
index.html?t=1715829304),绕过缓存 - 如果题目含图片或音频,解析里别直接写
<img src="...">,用loading="lazy"防止首屏卡顿
最易被忽略的是移动端 touch 延迟和 input 失焦冲突——比如在 iOS 上点选项后立刻点「下一题」,可能触发两次 click。加个 setTimeout 或节流就行,但很多人根本没想到这层。



















