简介:这是一份面向网页设计初学者的HTML+JavaScript随机点名器源码,适合教师、主持人在课堂或活动中快速点名。工具通过上传txt文档导入姓名列表,点击按钮即可随机抽取一人并展示结果,界面简洁,交互反馈即时。压缩包共7个文件,包含4个HTML页面(随机点名、随机不重复点名等不同版本)、2个编码格式的txt名单文件(兼容GBK与UTF-8)以及1个JavaScript脚本,整体仅11KB,结构紧凑、便于部署。已有318人学习浏览,是练手和二次开发的好素材,资源涵盖了表单元素、文件选择、FileReader读取、按行分割、数组随机索引及DOM更新等关键知识点,代码注释友好、思路清晰。读者可以直接套用,也可以修改名单、样式或增加动画效果;两种编码的txt名单能适应不同环境,随机不重复版本则适合多次点名的场景,可满足教学展示、活动抽选等多种需求。
1. 从 txt 名单到随机点名器:一个网页设计小工具的实战拆解
随机点名器这个需求,在网页设计里属于短小但五脏俱全的那类。它不需要后端,不用数据库,一个浏览器、一个 txt 文件、几段 JavaScript 就能跑通,但文件读取、编码处理、数组操作、随机算法——前端日常容易踩的坑几乎都能在这里遇到。我会按实际开发顺序把这个项目从压缩包里的原始文件开始拆开:先看清文件结构,再逐段读代码,然后说清楚最容易翻车的几个坑,最后给出一个能迁移到抽题、抽奖场景的自定义方案。适合正在做网页设计作业、或者想在课堂上快速点名又不想装任何软件的老师、助教和学生。
2. 随机点名器项目拆解:文件构成与双编码名单的设计意图
解压随机点名器.zip之后,第一眼看到的是好几个文件挤在一起,光是 HTML 就有四份。第一次接触这个项目的人多半会犹豫:到底该打开哪个文件?哪个才是真正能用的版本?
2.1 压缩包里每个文件的真实身份
先把文件清单和它的实际作用对齐,看清楚再动手:
| 文件 | 类型 | 实际作用 |
|---|---|---|
index.html | HTML | 常规入口页面,浏览器默认打开的就是它 |
随机点名器.html | HTML | 基础版点名页,只做最单纯的随机抽取 |
随机不重复点名器.html | HTML | 增强版点名页,做到“本轮点名不重复” |
temp.html | HTML | 开发过程里留下的临时调试页,正式用不到 |
随机点名器 js/shit.js | JavaScript | 核心逻辑脚本,负责读文件、拆名单、随机抽取 |
名单-gbk.txt | txt | GBK 编码的名单样例,适合 Windows 记事本场景 |
名单-utf8.txt | txt | UTF-8 编码的名单样例,跨平台更稳 |
其中index.html沿用了网页设计的命名惯例,在本地双击或者放到服务器上访问时,它会被默认加载。随机点名器.html和随机不重复点名器.html是开发过程中拆出来的两个功能版本:前者每次点击都从完整名单里抽一个人,完全随机;后者每次抽完会把被抽中的人从候选池里移除,避免同一个人被点到两次。
这两个版本的核心差别在于候选数据是否可变。“只需要随机抽一个人看看是谁”,那一个数组加Math.random()就完了;“还要保证这节课所有被点过的人都不重复”,就必须维护一个“还没被点到的人”的数组,每点一次就少一个。课堂点名场景里几乎都是后者,这也是为什么项目里单独做了一个“随机不重复”版本。temp.html属于开发过程中的调试产物,里面可能有实验性的样式或者临时代码,用来验证某个交互想法,正式交付时可以直接忽略。
然后是整个项目真正的核心shit.js。文件名起得随意,但几个 HTML 页面只是骨架,真正干活的全在这个脚本里:从input取文件、用FileReader读内容、按换行符拆数组、过滤空行、随机抽取、把结果写回页面。HTML 文件里通过<script src="shit.js"></script>引用它。文件名你可以随便改,但引用路径必须同步改,否则页面打开之后什么功能都没有。
2.2 名单-gbk.txt 和名单-utf8.txt:双编码背后的兼容逻辑
讲编码之前先说一个习惯:写网页时不能只看浏览器里的显示效果,要留意文件本身的编码。HTML 文件会在<meta>标签里声明字符编码,但 txt 文件没有这个声明。浏览器读取 txt 文件时,FileReader默认按 UTF-8 解码。而 Windows 自带记事本在简体中文系统上保存 txt 时,默认格式是 ANSI,也就是 GBK 编码。
于是最经典的错位出现了:页面声明 UTF-8,名单文件是 GBK,读出来全变乱码。这不是随机点名器独有的问题,凡是网页里要做“导入 txt 数据”的功能都会撞上。项目里直接放了两份名单,名单-gbk.txt和名单-utf8.txt,内容相同、编码不同,就是让你在不同环境下都有一份能用的。用哪一份,取决于你的名单文件来源——Windows 记事本手工建的名单大概率是 GBK,VS Code 或 macOS 编辑器里建的大概率是 UTF-8。
如果你想把编码问题在代码层面一次性解决,可以用TextDecoder显式指定解码规则。这个做法要在读取文件时换一个 API 入口:
const reader = new FileReader(); reader.onload = function (event) { // 用 ArrayBuffer 拿到原始字节,而不是已经被解码的字符串 const buffer = event.target.result; const decoder = new TextDecoder('gbk'); const content = decoder.decode(buffer); // 按行拆分,去掉首尾空格,过滤空行 const names = content.split('\n').map(n => n.trim()).filter(n => n.length > 0); console.log(names); }; reader.readAsArrayBuffer(file);这段代码里最关键的是readAsArrayBuffer替换了readAsText。readAsText在读取时内部已经按 UTF-8 做了解码,一旦文件实际编码不匹配,数据在回调里就已经损坏,后面再补救都来不及。而readAsArrayBuffer拿到的是原始字节,你可以用TextDecoder在后面自由指定解码规则。TextDecoder('gbk')在现代浏览器里支持得不错,但老版本浏览器和某些特殊环境不一定认,项目采用双名单方案,本质上也是为了避免过度依赖某个 API 的兼容性。
2.3 从文件选择到结果展示:点名器的整体工作流
把点名器的运行流程完整拆成步骤,后面读代码时可以逐一对号入座:
- 页面加载,渲染出文件选择框、点名按钮和结果展示区。
- 用户选择 txt 文件,
input元素的change事件触发。 - JavaScript 从
event.target.files[0]拿到File对象。 - 创建
FileReader实例,调用readAsText或readAsArrayBuffer读取文件。 - 读取成功后,在
onload回调里把拿到的字符串按\n分割成数组。 - 对数组做去空行、去首尾空格处理,得到一个干净的名字列表。
- 点击点名按钮时,从数组里随机取一个下标,把名字显示到页面上。
- 如果是“不重复”版本,把被点到的名字从候选数组里删掉。
第 5 步到第 7 步是核心逻辑,也是最容易翻车的地方。文件读取是异步的,如果你在调用readAsText之后立刻用files[0].result去取值,大概率拿到的是null。正确做法是在onload回调里处理数据,或者把FileReader封装成 Promise 再用await拿结果。很多第一次接触 FileReader 的人都会卡在这里。
异步还有一个容易被忽略的连带问题:如果你想把这个名单数组保存下来供按钮点击时使用,必须确认赋值发生在onload回调里。文件加载完成之后,数组才被赋值到全局变量;如果赋值时机没控制好,比如代码顺序写在了readAsText调用后面、但实际上onload还没触发,那点按钮时数组还是空的,抽出来的人自然是undefined。
3. 用 JavaScript 实现 txt 名单导入与随机点名:代码逐段拆解
前面文件结构搞清楚了,这章开始写代码。我会把项目里几个 HTML 文件的公共核心抽出来,按“页面结构 → 文件读取 → 随机点名 → 完整组装”四步拆解,每一步都能直接抄走。
3.1 页面结构:一个文件选择框、一个按钮、一个结果区域
先写 HTML 骨架。把几个 HTML 文件的核心结构提炼出来,最简版本就是下面这样:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>随机点名器</title> <style> body { font-family: "Microsoft YaHei", sans-serif; max-width: 600px; margin: 40px auto; text-align: center; } #result { font-size: 48px; color: #333; min-height: 60px; margin: 24px 0; } button { padding: 10px 20px; font-size: 18px; } </style> </head> <body> <h1>随机点名器</h1> <input type="file" id="nameFile" accept=".txt,text/plain"> <button id="startBtn">开始点名</button> <button id="resetBtn" disabled>重置名单</button> <p id="result">点击按钮开始</p> <p id="status">尚未加载名单</p> <script src="shit.js"></script> </body> </html>页面结构有三个关键点。第一,<input type="file">的accept属性同时写了.txt和text/plain,作用是限制文件选择框只显示可用的文本文件,避免用户误选图片或 Word 文档。第二,所有元素都用id标记,JavaScript 里全靠getElementById定位,id 拼错一个字母整个功能就废了,复制粘贴时要重点检查。第三,result和status两个区域分开,一个是点名结果的大字展示,一个是文件加载状态的小字提示。这样用户能分清“名单还没加载”和“点到了谁”是两件事。
页面底部通过<script src="shit.js"></script>引入外部脚本。这里有个实用经验:脚本文件放 body 末尾,HTML 元素先全部渲染完再执行 JS,getElementById才能拿到节点。放到<head>里需要额外包DOMContentLoaded事件,没必要。
3.2 FileReader 读取 txt 文件:核心 API 的使用方式
脚本部分先从读取文件开始。点名器的数据源是 txt,读取逻辑能不能扛住,直接决定后面所有功能能不能跑。
let namePool = []; // 完整名单,永不被修改 let currentPool = []; // 当前候选池,不重复点名时会被删元素 const fileInput = document.getElementById('nameFile'); const startBtn = document.getElementById('startBtn'); const resultEl = document.getElementById('result'); const statusEl = document.getElementById('status'); const resetBtn = document.getElementById('resetBtn'); fileInput.addEventListener('change', function (event) { const file = event.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = function (e) { const content = e.target.result; const lines = content.split('\n'); // 先去掉每行首尾空格和回车符,再过滤掉空行 const names = lines.map(line => line.trim()).filter(name => name.length > 0); if (names.length === 0) { statusEl.textContent = '名单为空,请检查 txt 文件'; return; } namePool = names.slice(); currentPool = names.slice(); statusEl.textContent = '已加载 ' + names.length + ' 人'; resetBtn.disabled = false; resultEl.textContent = '准备就绪'; }; reader.onerror = function () { statusEl.textContent = '文件读取失败'; }; reader.readAsText(file, 'UTF-8'); });这段代码的流程是:拿到File对象后创建FileReader,监听onload事件,在回调里e.target.result就是文件内容字符串。按\n分割成lines数组,然后链式调用trim()去掉每行首尾的空格和\r回车符,再用filter过滤掉空行,得到一个干净的名字数组。
代码里namePool和currentPool是两个变量,这是“不重复点名”的核心前提。namePool是完整名单的备份,从头到尾不动;currentPool是当前侯选池,每次点名后会被删除元素。为什么非要存两份?因为在点名过程中currentPool会越变越短,如果没有namePool保留原始数据,你就永远不知道最初名单里有多少人,也没法一键重置回到完整状态。第一次写这个功能的人经常只用一个数组,点了几轮名字之后发现名单越来越少,就是没有备份原始数据的后果。
readAsText(file, 'UTF-8')的第二个参数是编码。这里要特别提醒:如果你拿到的是名单-gbk.txt,强制指定 UTF-8 就会按错误规则解码,轻则个别生僻字变乱码,重则整页方块。所以这个参数不是写死就完事的,它必须跟你的 txt 文件编码对应。
3.3 随机不重复点名:从随机下标到 Fisher-Yates 洗牌
文件读取成功之后,点名逻辑本身反而很简单。最基本的随机抽取只需要一个数组下标:
function pickRandomName() { if (currentPool.length === 0) { resultEl.textContent = '所有人都已点过'; return null; } const randomIndex = Math.floor(Math.random() * currentPool.length); const selected = currentPool[randomIndex]; // 把被点到的名字从候选池中移除,实现本轮不重复 currentPool.splice(randomIndex, 1); resultEl.textContent = selected; return selected; }这段代码的灵魂在splice(randomIndex, 1)。先解释随机下标:Math.random()生成 0 到 1 之间的浮点数,乘以数组长度得到 0 到 length 之间的浮点数,再用Math.floor向下取整,得到合法的整数下标。这一步缺了Math.floor,拿到的就是小数,数组取不到元素;缺了乘以长度,拿到的永远只是前几个下标。这是随机取数组元素最容易写错的地方。
currentPool.splice(randomIndex, 1)的意思是从下标randomIndex开始删除 1 个元素,并把这个元素作为返回值。它同时完成两件事:取出名字、从候选池里移除。这样下一次调用pickRandomName时,这个人的名字已经不在数组里了,不会再次被抽中。
如果想让点名过程有一些“仪式感”,这里还有一个小技巧:先用setInterval每隔几十毫秒随机显示一个名字,屏幕上的名字不断跳动,等停止时再显示最终结果。看起来像抽奖滚轮,实际原理只是临时把数组打乱展示,最终停在splice选中的那个名字。注意停止时要clearInterval,否则定时器永远在跑,页面会卡顿。
从性能角度多说一句:splice删除数组元素的时间复杂度是 O(n),因为删除后要把后续元素向前移动。课堂名单一般几十人,完全没压力。如果你要做上千人的大规模点名,可以考虑 Fisher-Yates 洗牌:一次性把数组随机打乱,之后每次点名直接取队首元素,经过一轮之后刚好把所有人都点一遍,复杂度更优。洗牌算法从实现上稍微复杂一点,普通课堂场景用splice就够,洗牌属于性能洁癖者的进阶选择。
3.4 完整代码:把读取、点名、展示串起来
把前面几段合到一起,补上重置按钮和键盘快捷键逻辑,就得到一个能独立运行的单页点名器:
// 重置候选池,恢复全体名单 resetBtn.addEventListener('click', function () { currentPool = namePool.slice(); resultEl.textContent = '已重置'; statusEl.textContent = '候选人数:' + currentPool.length; }); // 空格键触发点名,preventDefault 防止页面滚动 document.addEventListener('keydown', function (event) { if (event.code === 'Space' && currentPool.length > 0) { event.preventDefault(); pickRandomName(); } }); startBtn.addEventListener('click', pickRandomName);这里有两个细节值得说明。空格键监听用的是event.code === 'Space',而不是event.key === ' '。code表示物理按键,key表示输入字符,在中文输入法开启状态下,空格键的key可能变成空格之外的字符,用code判断更稳。另外preventDefault()是为了阻止空格触发页面滚动,否则长页面下按空格点名会导致页面上下跳动。
组装后完整使用路径是:双击打开index.html或随机点名器.html,点击选择文件,选中名单-utf8.txt,状态栏显示加载人数,再点击按钮或按空格键,结果大字显示。逻辑全部在shit.js里,HTML 只负责结构和样式。这个解耦结构在维护时很舒服——换点名逻辑只改 JS,换界面只改 HTML。
4. 随机点名器避坑指南:编码乱码、空行、重复点名与误操作
这个项目整体不复杂,但有几个坑属于“不踩不知道、一踩就当场翻车”的类型。尤其课堂场景下,你站在讲台上当众演示,名字显示乱码或者点出空名字,非常尴尬。以下四条是我实际使用和帮人排查时遇到最多的问题。
4.1 读取 GBK 名单显示乱码
现象:选择名单-gbk.txt之后,页面上显示的名字全是乱码,常见的是“鏉庣帇”“寮犱笁”这类完全不可读的字符,英文名正常,中文名全部阵亡。
原因是编码不匹配。FileReader.readAsText默认按 UTF-8 解码,而 GBK 是中文 Windows 系统的本地编码,两者对同一个字节序列映射出来的字符完全不同。UTF-8 中文字符是三个字节,GBK 是两个字节,解码错位之后名字内容直接损坏。这个坑在 Windows 上做网页设计时尤其容易踩,因为记事本默认存出来的就是 GBK。
解决方案按推荐顺序排列。第一种,把 txt 另存为 UTF-8:用记事本打开名单,点“另存为”,编码下拉框选 UTF-8,重新导入即可。第二种,直接用项目里的名单-utf8.txt这份现成的。第三种,代码层面用TextDecoder('gbk')配合readAsArrayBuffer读取,前面 2.2 节里有一段完整代码,适合你要在代码里一次性兼容两种编码、不能要求用户手工改文件的情况。
4.2 名单末尾空行导致点名失败
现象:名单读进来了,总人数显示也正常,但点名偶尔会跳出一个空白名字,页面状态像卡住一样,结果区域什么都不显示。
原因是 txt 文件末尾几乎总有一个换行符。按\n分割之后,最后一个数组元素是空字符串。如果随机下标正好落在最后一个位置,抽到的就是空字符串,显示出来自然是一片空白。名单越短,出问题的概率越高——5 个人的名单有 1/5 概率抽到空行,这个概率一点都不低。
解决方式就是分割后立刻过滤。前面代码里已经写了map(line => line.trim()).filter(name => name.length > 0),这里要特别强调顺序:先trim()再filter。如果只过滤空字符串不过滤空格,那“张三 ”这种带一个尾部空格的元素,length不为 0,会通过过滤,显示的时候名字旁边带一个奇怪的空白缩进。养成trim在前后、filter在后的习惯,能避免这类连带问题。
4.3 点过的人再次被点到
现象:用的是随机点名器.html这个基础版,同一个名字隔几分钟又被抽到。课堂场景下,老师点过一次之后会要求“再换一个没点过的”,于是当场翻车。
原因是基础版从头到尾只做随机抽取,不维护状态。每个名字在每次点名时被抽中的概率完全相等,这是随机算法的正常表现,不是 bug。但课堂点名需求默认就是“本次不重复”,所以必须用带候选池管理的版本。
解决要分两层。如果只想“本轮点名不重复”,用currentPool数组加splice移除即可,前面 3.3 的代码已经实现了。如果想跨多节课、甚至跨一整学期都不重复,就得把历史记录存到localStorage,每次加载名单时和上次记录做差集,得到“当前还没被点过的所有人”。后者逻辑上稍微复杂,但思路不绕:当前可用名单 = 全部名单 - 历史名单。
4.4 文件选择框没有限制 accept 导致误选
现象:文件选择框点击之后弹出的是所有类型的文件,用户随手选了一张图片或一个 Word 文档,点名器状态显示异常,或者直接没反应。
原因是<input type="file">上没写accept属性,或者只写了.txt。不同操作系统对 MIME 类型的处理有差异,Windows 上.txt的 MIME 类型是text/plain,只写.txt在部分浏览器里也能用,但不是所有浏览器都认。
解决方式是双保险。accept属性写成accept=".txt,text/plain",覆盖主流系统。同时在 JS 代码里加一道扩展名检查:读取之前先判断文件名是否以.txt结尾,不是就直接提示“请选择 txt 名单文件”并 return,从源头阻断错误。这道兜底判断加上之后,即使accept在某些特殊环境下失效,也不至于让程序带病运行。
5. 进阶:给点名器加历史记录、快捷键与视觉反馈
基础功能跑通之后,离“真正在课堂上用得顺手”还有一段距离。这章加三个常用能力:历史记录、键盘操作、视觉反馈,最后说说怎么把这个项目迁移到抽题和抽奖场景。
5.1 被点名单的历史记录与一键重置
课堂点名不只是抽个人出来,老师往往还要记录“这节课点了谁”。在点名器里加一个历史记录列表,把所有被点到的人按顺序显示出来,下课直接对照名单核对。
let history = []; function pickRandomName() { if (currentPool.length === 0) { resultEl.textContent = '所有人都已点过'; return null; } const randomIndex = Math.floor(Math.random() * currentPool.length); const selected = currentPool[randomIndex]; currentPool.splice(randomIndex, 1); history.push(selected); renderHistory(); resultEl.textContent = selected; return selected; } function renderHistory() { const listEl = document.getElementById('historyList'); // map 生成 li,join 拼接后一次性写入,避免多次操作 DOM listEl.innerHTML = history.map(function (name, index) { return '<li>' + (index + 1) + '. ' + name + '</li>'; }).join(''); }history和currentPool是互补的:currentPool在减少,history在增加,两者的长度之和始终等于原始名单的namePool.length。这是一个很好的自检指标,如果这个等式不成立,说明代码里某处误删了数组元素,排查逻辑错误时可以直接利用它定位问题。
如果想跨浏览器会话保存历史记录,把history序列化之后存到localStorage就行:
function saveHistory() { localStorage.setItem('history', JSON.stringify(history)); } function loadHistory() { const saved = localStorage.getItem('history'); if (saved) { history = JSON.parse(saved); renderHistory(); } }页面加载时调用loadHistory(),每次点名后调用saveHistory()。注意localStorage只能存字符串,数组必须JSON.stringify之后才能存,读出来再用JSON.parse还原。这个跨会话存储做出来后,即使关闭浏览器,上节课点过的人也不会丢失,下一节课继续点就能自动避开。
5.2 增加键盘快捷键和视觉反馈
课堂环境下老师不总握着鼠标,用空格键点名的顺畅程度远高于移鼠标点按钮。前面 3.4 节的代码已经写了一个基础的keydown监听,这里补一个视觉反馈细节:点名成功后给结果区域加一个短暂的背景闪烁,让后排学生也知道被点到的是谁。
先加一点 CSS 过渡:
#result.flash { background-color: #fff3cd; transition: background-color 0.3s; }再在pickRandomName里加上类名切换:
resultEl.textContent = selected; resultEl.classList.add('flash'); // 600ms 后移除高亮,保证下一次点名能重新触发 setTimeout(function () { resultEl.classList.remove('flash'); }, 600);闪烁效果的时间控制在 0.5 到 0.8 秒之间比较合适,太短看不清,太长拖慢节奏。这里有个小习惯:类名添加之后一定要用定时器移除,否则下一次点名时元素已经带着flash类,视觉上不会有重新闪烁的效果,看起来就像功能失效了。
如果想给名单加“快速定位”,还有一个小技巧:把历史列表里的某个人点击后,调用scrollIntoView让页面滚动到对应位置。这个功能在几十人的小班意义不大,但如果是几百人的大课,老师想快速找到某个学生时,点一下记录里的名字就能定位,提升明显。
5.3 场景扩展:不只是点名,也可以抽题、抽奖
把名单从“学生名字”换成“题目编号”、“奖品名称”,点名器瞬间变成抽题器或抽奖器。改的只是读取的文件内容,代码逻辑一行都不用动。我在实际使用中会把页面标题从“随机点名器”改成“课堂助手”,同一套 HTML 文件在不同课程场景里复用。
这里有一个边界值得注意:抽奖虽然和点名一样需要“不重复”,但抽奖通常还要记录抽取顺序,用来决定一等奖、二等奖的对应关系。当前面的history数组按抽取顺序保存后,它本身就是一份完整的中奖记录——第一个进入history的就是一等奖,第二个是二等奖,依此类推。做公开展示时,把renderHistory的输出加一个“中奖顺序”的前缀说明即可,不需要额外开发新功能。
如果点名场景还需要“按概率加权”,比如某些学生课堂表现好、中奖概率翻倍,那就要在随机抽取逻辑上做文章。最直接的做法是把名单复制成多份,在复制后的数组里随机抽取。比如张三要双倍概率,就把张三这个名字在数组里放两遍。这个做法简单但对内存不友好,几千人的名单复制之后数组会变得很大。另一种做法是维护一个权重数组,按权重区间生成随机数再锁定对应名字,实现略复杂,但思路对规模化场景更友好。课堂点名用不到这么细,了解有这条路就行。
6. 用自己的名单验证点名器:五步检查清单与最后的细节
准备自己的 txt 名单通常是这样:打开记事本,每行写一个名字,保存时编码选 UTF-8,文件名随便起,比如我的名单.txt。然后在浏览器里打开index.html,选择这个文件,确认状态显示的人数和你名单里的行数一致。这一步如果就出现偏差,先检查是不是有多余空行或末尾多了一个换行。
第一步验证读取:名单加载后,在浏览器控制台输入console.log(currentPool),确认数组里的名字都是完整且正常的。这一步能立刻看到trim和filter是否生效,有没有遗留的空字符串或带空格的名字。第二步验证不重复:连续点击按钮把所有人都点一遍,确认每个人只出现一次,点完后页面提示“所有人都已点过”。如果中途有人被点到两次,说明currentPool没有正确移除元素,检查splice的下标和长度参数。第三步验证重置:点名进行到一半,点击重置按钮,候选人数恢复为总数,历史记录清空,后续点名正常进行。第四步验证编码:用记事本另存一份 GBK 编码的名单,再次加载,确认是否乱码,由此判断你的代码对编码不匹配的容错程度。第五步验证快捷键:不碰鼠标,只用空格连续点名,确认不会触发页面滚动或者按钮误点。
从那次以后,我每次拿到新的名单或者改完 JS 代码,都会强制走一遍这五步再交付。之前有一次图省事,直接拿 GBK 名单去测 UTF-8 的代码,页面显示乱码,排查了十几分钟才发现是编码问题。那之后我就在自己的检查清单里加了一条铁律:编码验证永远是第一步。随机点名器技术上不复杂,但文件编码、空行过滤、数组状态管理这几个细节不做对,关键时刻就是你站在讲台上当着全班面翻车的瞬间。希望这篇拆解能帮你在动手之前把这些坑填平。
本文还有配套的精品资源,点击获取