简介这是一款模拟高考成绩查询的网页小程序面向刚结束高考、正处于等分焦虑期的考生也适合想体验查分流程或做前端练手的开发者。页面以娱乐为目的目前仅支持甘肃省输入信息后即可看到一份“比梦里还高”的模拟成绩用来缓解等待真实分数时的紧张情绪。资源包共30个文件约1.41MB包含3个html页面登录、开始、结果、7个js脚本、3个css样式以及10张jpg、4张png、1张gif图片素材另有license与readme.pdf说明文档前端结构完整可直接在浏览器中运行体验。压缩包内还带有jQuery、表单验证、加密与轮播等常用插件适合作为小型静态项目的参考。目前已有1835人学习下载读者可借此了解多页面跳转、表单校验与结果展示的实现思路也能快速替换文案与图片改造成自己的趣味查分页面。1. 模拟高考成绩查询小程序 html一个页面就能跑通的查分交互原型每年查分季后台总有人问能不能用最轻的方式做一个「模拟高考成绩查询小程序 html」页面不接后端、不买服务器双击就能演示答案是可以而且核心代码不到两百行。它解决的不是真实查分而是把「输入准考证号 → 校验 → 展示分数 → 分科明细」这条交互链路完整跑通适合做教学演示、产品原型、前端练手或者给非技术同事看效果。HTML 负责结构CSS 负责观感JavaScript 负责假数据生成和状态切换三者合起来就是一个自包含的查分页。下面按「先立住原理、再动手复现、最后讲坑」的顺序拆开讲每一步都能直接抄。2. 查分页面的技术选型为什么纯前端 HTML 就够用2.1 模拟查分和真实查分的边界在哪真实高考查分系统背后是省级考试院的数据接口涉及身份核验、并发限流、加密传输前端只是薄薄一层壳。而「模拟」二字的含义是数据不来自远端由本地脚本按规则生成。这个边界决定了技术选型——不需要框架、不需要构建工具、不需要网络请求。一个.html文件内嵌style和script浏览器打开即用。常见做法是直接用原生 DOM 操作而不是引入 Vue 或 React。原因有三第一页面只有一个视图切换逻辑状态简单第二演示场景往往要发给别人单文件最省事第三新手能看清每一行在干什么不会被框架的响应式黑盒挡住。我一般会建议先用原生写一遍理解事件绑定和 DOM 更新再考虑要不要上框架。需要明确的是这个页面不存储任何真实考生信息。准考证号只作为「生成种子」参与伪随机计算刷新页面后同一号码会得到同一结果换一个号码结果就变。这种确定性对演示很重要——你不能让观众输同一个号两次看到不同分数那会显得很假。2.2 单文件结构HTML、CSS、JS 各管什么单文件不等于乱堆。结构上分三块head里放样式body里放两个视图容器查询表单和结果面板script放逻辑。视图切换靠 CSS 类控制显隐而不是删除重建 DOM这样切换有过渡感也避免重复绑定事件。下面是最小骨架先建立这个结构后面所有功能都往里填!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title模拟高考成绩查询/title style /* 样式区控制两个视图的显隐和卡片观感 */ .view { display: none; } .view.active { display: block; } /style /head body !-- 视图一查询表单 -- section idqueryView classview active input idexamId typetext placeholder请输入准考证号 button idqueryBtn查询/button /section !-- 视图二结果面板 -- section idresultView classview div idscoreBoard/div button idbackBtn返回/button /section script // 逻辑区后续所有函数写在这里 /script /body /html这段骨架的关键点是view和active两个类。默认查询视图带active结果视图不带所以打开只看到表单。切换时用 JS 增删active类即可。meta viewport不能省否则手机浏览器会按桌面宽度渲染输入框小得没法点。准考证号输入框用typetext而不是number因为真实准考证号可能含字母且number类型在部分浏览器会带上下箭头观感差。2.3 伪随机分数生成让同一个号码永远得到同一结果模拟查分最核心的一步是「号码决定分数」。如果每次刷新都随机演示就穿帮了。做法是把准考证号字符串转成一个整数种子再用这个种子驱动一个确定性伪随机函数。常见做法是简单的哈希逐字符取编码累加并乘一个质数得到一个 32 位整数。// 把准考证号转成确定性种子同一字符串永远得到同一整数 function hashSeed(str) { let seed 0; for (let i 0; i str.length; i) { // 31 是常用质数累乘能让字符顺序影响结果 seed (seed * 31 str.charCodeAt(i)) 0; } return seed; } // 线性同余伪随机输入种子返回 0~1 之间的小数 function seededRandom(seed) { // 取一个常见的大质数做模保证分布均匀 const x Math.sin(seed) * 10000; return x - Math.floor(x); }hashSeed里用 0是为了把结果强制转成无符号 32 位整数避免负数参与后续运算导致分布偏移。seededRandom用Math.sin做混淆是取巧写法好处是短、无需维护状态如果对分布要求更高可以换成 mulberry32 之类的标准算法。参数上seed每次调用前加一个固定偏移比如加科目索引就能让同一考生不同科目得到不同但稳定的分数。生成单科分数时把种子映射到合理区间。语数外满分 150综合满分 300模拟时按比例缩放// 根据种子生成指定区间的整数分数 function scoreFromSeed(seed, min, max) { const r seededRandom(seed); return Math.floor(min r * (max - min 1)); } // 生成六科成绩科目索引参与种子偏移 function buildScores(examId) { const base hashSeed(examId); return [ { name: 语文, score: scoreFromSeed(base 1, 90, 150), full: 150 }, { name: 数学, score: scoreFromSeed(base 2, 80, 150), full: 150 }, { name: 外语, score: scoreFromSeed(base 3, 85, 150), full: 150 }, { name: 物理, score: scoreFromSeed(base 4, 60, 100), full: 100 }, { name: 化学, score: scoreFromSeed(base 5, 60, 100), full: 100 }, { name: 生物, score: scoreFromSeed(base 6, 60, 100), full: 100 } ]; }区间下限不是 0是为了让结果看起来像真实考生——没人六科全考个位数。full字段存满分渲染时用来算百分比和画进度条。这套生成逻辑的确定性来自hashSeed只要准考证号不变六科分数永远一致演示时反复查询不会露馅。3. 从输入到出分把查询交互一步步接起来3.1 表单校验三种非法输入必须拦在查询前查询按钮点下去之前至少拦三类输入空值、长度不符、含非法字符。真实准考证号通常是 14 位数字模拟时按这个规则校验既真实又好实现。校验不通过时不要弹alert那会打断演示节奏改成在输入框下方显示一行红字提示。// 校验准考证号返回 { ok: boolean, msg: string } function validateExamId(id) { if (!id) { return { ok: false, msg: 请输入准考证号 }; } if (!/^\d{14}$/.test(id)) { return { ok: false, msg: 准考证号应为 14 位数字 }; } return { ok: true, msg: }; }正则^\d{14}$里的^和$不能省否则12345678901234abc这种也会通过test。返回对象而不是布尔值是为了把提示文案一起带出来调用方不用再判断该显示哪句话。如果要做更宽松的演示可以把长度改成 8 到 16 位但正则要相应调整别留下能注入 HTML 的口子——虽然这里不涉及后端但把用户输入直接塞进innerHTML是坏习惯后面渲染时会用textContent规避。3.2 视图切换与结果渲染用 DOM 操作替代页面跳转点击查询后先校验通过则生成分数、渲染结果、切到结果视图。整个过程不刷新页面靠类名切换。渲染分数时用createElement和textContent而不是拼字符串塞innerHTML这样即使输入框里有人塞了奇怪字符也不会被当标签解析。// 渲染成绩面板 function renderResult(examId) { const scores buildScores(examId); const total scores.reduce((sum, s) sum s.score, 0); const board document.getElementById(scoreBoard); board.textContent ; // 清空上一次结果 const title document.createElement(h2); title.textContent 准考证号 examId 的成绩; board.appendChild(title); scores.forEach(function (item) { const row document.createElement(p); // 用 textContent 拼接避免 HTML 注入 row.textContent item.name item.score / item.full; board.appendChild(row); }); const totalLine document.createElement(p); totalLine.textContent 总分 total; board.appendChild(totalLine); }reduce求总分时初始值传 0不能省否则空数组会抛错。board.textContent 是清空子节点的简洁写法比innerHTML 更安全。每科一行用p而不是div语义上更接近段落文本。如果要做进度条可以在每行后面追加一个span用style.width按score / full设百分比但要注意宽度值要拼上%单位。3.3 事件绑定与状态复位返回后能再次查询查询按钮和返回按钮各绑一个监听。返回时把结果视图的active去掉、查询视图加上同时清空输入框和错误提示让页面回到初始状态。这样连续演示多个号码时不会残留上一次的痕迹。document.getElementById(queryBtn).addEventListener(click, function () { const input document.getElementById(examId); const id input.value.trim(); const check validateExamId(id); const tip document.getElementById(tip); if (!check.ok) { tip.textContent check.msg; return; } tip.textContent ; renderResult(id); document.getElementById(queryView).classList.remove(active); document.getElementById(resultView).classList.add(active); }); document.getElementById(backBtn).addEventListener(click, function () { document.getElementById(resultView).classList.remove(active); document.getElementById(queryView).classList.add(active); document.getElementById(examId).value ; document.getElementById(tip).textContent ; });input.value.trim()去掉首尾空格防止用户复制粘贴时带入空白导致校验失败。错误提示元素tip需要提前在 HTML 里放好位置在输入框下方。返回时清空输入框是刻意的——如果不清下次点查询会直接复用旧号码演示时容易让人误以为没生效。事件监听用addEventListener而不是onclick属性后者会覆盖同名属性多个脚本协作时容易互相踩。4. 避坑与排查模拟查分页面最容易翻车的五个地方4.1 刷新后分数变了现象同一个准考证号第一次查是 580 分刷新页面再查变成 610 分。原因分数生成用了Math.random()没有走确定性种子。解决把生成逻辑全部换成hashSeed加seededRandom确保输入相同则输出相同。检查方法是把准考证号写死成常量连续刷新十次分数应完全一致。4.2 手机上看输入框被键盘挡住现象在手机上点输入框弹出键盘后查询按钮被顶出可视区域用户得先收键盘才能点。原因页面没有做移动端适配或者按钮固定在底部但没考虑键盘高度。解决给body加padding-bottom按钮用普通文档流而不是position: fixed输入框加inputmodenumeric让数字键盘弹出减少误输。如果必须固定按钮用env(safe-area-inset-bottom)处理底部安全区。4.3 输入特殊字符导致页面错乱现象在准考证号里输入script或img onerror...结果面板渲染出奇怪内容甚至弹窗。原因渲染时用了innerHTML拼接用户输入。解决所有用户输入一律走textContent或者渲染前做转义。这个坑在纯前端演示里看似无害但养成习惯后接后端时会避免 XSS。排查方法是搜代码里所有innerHTML逐个确认右侧是否含变量。4.4 连续点击查询按钮出现重复内容现象快速点两下查询结果面板里成绩出现两遍。原因renderResult里没有先清空容器appendChild是追加而不是替换。解决在渲染函数开头加board.textContent 。更稳妥的做法是给按钮加一个短暂的禁用状态防止连点但清空容器是根本解法。排查时看结果面板的子节点数量正常应等于科目数加两行标题和总分。4.5 准考证号带空格校验不通过现象用户从别处复制号码末尾带了一个空格点查询提示格式错误但肉眼看不出来。原因校验前没做trim。解决取值时统一input.value.trim()校验和生成种子都用 trim 后的值。注意trim只去首尾空白中间的空格仍会被正则拦下这是符合预期的。如果业务允许中间有分隔符正则要相应放宽但模拟场景没必要。5. 进阶技巧把单文件查分页做成可演示的完整作品单文件能跑通只是起点。要让它在演示场合站得住还得补三样东西视觉层次、异常兜底、可分享性。视觉上给分数面板加一个总分环形或条形进度用纯 CSS 的conic-gradient就能画不需要图表库。具体做法是给总分算一个相对满分的百分比把百分比作为conic-gradient的角度参数外圈用border-radius: 50%裁成圆环中间用绝对定位放总分数字。这样截图发出去比纯文字有说服力。异常兜底方面除了前面说的校验还要考虑「查询中」的过渡态。真实系统有网络延迟模拟页面如果点完瞬间出结果反而显得假。可以在点击后加一个 300 到 500 毫秒的setTimeout期间把按钮文字改成「查询中…」并禁用再切视图。这个延迟不要超过 800 毫秒否则演示时会让人等得不耐烦。代码如下// 带过渡态的查询处理 function handleQuery() { const btn document.getElementById(queryBtn); const id document.getElementById(examId).value.trim(); const check validateExamId(id); if (!check.ok) { document.getElementById(tip).textContent check.msg; return; } btn.disabled true; btn.textContent 查询中…; // 模拟网络延迟提升真实感 setTimeout(function () { renderResult(id); document.getElementById(queryView).classList.remove(active); document.getElementById(resultView).classList.add(active); btn.disabled false; btn.textContent 查询; }, 400); }可分享性指的是把页面发给别人时不用附带说明。做法是在页面底部加一行小字写明「本页面为模拟演示数据由本地算法生成与任何真实考试机构无关」。这行字既是免责也让演示对象立刻明白性质避免误会。另外把准考证号输入框的placeholder写成「请输入 14 位准考证号」比只写「请输入准考证号」更能引导正确输入减少校验失败次数。最后说一个我踩过的坑早期版本我把分数生成逻辑写在渲染函数里结果每次切回查询视图再查因为种子重新计算分数虽然一致但科目顺序偶尔错乱。后来把生成和渲染拆成两个函数生成只依赖准考证号渲染只依赖生成结果问题就消失了。这个拆分习惯后来在做任何数据展示时都保留着——数据归数据视图归视图中间用纯函数隔开调试时能单独验证每一层。希望帮到你。本文还有配套的精品资源点击获取