Web-Dev-For-Beginners 实战:用事件驱动编程从零构建一个打字速度游戏

发布时间:2026/9/11 20:45:11
Web-Dev-For-Beginners 实战:用事件驱动编程从零构建一个打字速度游戏 Web-Dev-For-Beginners 实战用事件驱动编程从零构建一个打字速度游戏【免费下载链接】Web-Dev-For-Beginners24 Lessons, 12 Weeks, Get Started as a Web Developer项目地址: https://gitcode.com/GitHub_Trending/we/Web-Dev-For-Beginners本教程是 Web-Dev-For-Beginners 课程第 4 单元《事件驱动编程》的核心实战章节。你将理解浏览器如何通过「事件」与 JavaScript 代码通信并亲手搭建一个基于 Sherlock Holmes 名言、实时追踪打字速度与正确率的小游戏。读完本文你不仅能掌握addEventListener()、事件对象与 DOM 动态渲染的核心用法还能结合本仓库的官方 Solution 源码看到同一套逻辑从教学版演进为工程化 ES6 代码的完整路径。事件驱动编程让网页「活」起来的底层机制回顾任何一款让你感到「顺滑」的应用其灵魂都在于对用户操作的即时响应每一次点击、输入、滑动或按键浏览器都会产生一个被称为Event事件的消息并把它派发给你的代码由你决定如何处理。Web 编程的特殊之处在于不确定性——我们永远不知道用户何时会点击按钮或开始打字可能立即发生可能五分钟后也可能根本不发生。因此我们不能像写「菜谱」那样自上而下地执行代码而必须写「随时待命」的代码注册监听、等待触发、立即响应。这与 19 世纪守在电报机旁、一收到讯号就做出反应的电报员如出一辙。实现这一模式的核心工具就是Event Listener事件监听器。把它想象成安装在代码上的一枚门铃安装门铃 —— 调用addEventListener()告诉它监听哪种「铃声」 —— 传入事件类型如click、input指定响铃后的动作 —— 传入你的回调函数。事件监听器的四个核心能力监听特定的用户动作如点击、按键、鼠标移动事件发生时执行你编写的回调代码对用户输入即时响应营造无缝体验允许在同一个元素上通过不同监听器处理多个事件。关于创建监听器的多种方式你可以用匿名函数或具名函数也可以走捷径如直接给元素设置onclick属性还可以调用addEventListener()。本教程统一采用addEventListener() 匿名函数这是 Web 开发者最常用、也最灵活的方式——它对所有事件通用且事件名以参数形式传入。常用事件一览浏览器提供了大量事件可供监听但大多数交互式应用真正依赖的只是少数几个核心事件。下表列出最常见的四种其中click与input正是本游戏用到的两个事件描述常见使用场景click用户点击了某处按钮、链接、交互元素contextmenu用户按下鼠标右键自定义右键菜单select用户选中了一段文本文本编辑、复制操作input用户输入了文本表单校验、实时搜索这类事件类型的共同特性在用户与页面特定元素交互时触发通过事件对象携带关于用户动作的详细信息让我们得以构建响应式、可交互的 Web 应用在不同浏览器和设备上行为一致。游戏整体设计从点击 Start 到完成计时我们要构建的是一个测试玩家打字能力的游戏——这是每位开发者都应当掌握却被严重低估的核心技能。顺带一提我们今天使用的 QWERTY 键盘布局是 1870 年代为打字机设计的而对程序员来说良好的打字能力至今依然同样宝贵。游戏的整体流程如下游戏的核心行为点击 Start 按钮后开始并展示一条随机名言逐词实时跟踪玩家的打字进度高亮当前待输入的单词引导玩家注意力输入错误时即时给出视觉反馈名言完整输入后计算并展示总耗时。项目结构与开发环境搭建开工前先建立清晰的文件结构能让项目更专业、也避免日后的混乱。整个游戏只依赖经典「三件套」index.html—— 页面结构与内容script.js—— 全部游戏逻辑与事件监听器style.css—— 视觉外观与样式。打开终端创建项目目录# Linux 或 macOS mkdir typing-game cd typing-game # Windows md typing-game cd typing-game用 Visual Studio Code 打开项目code .在 VS Code 中依次新建三个文件index.html、script.js、style.css。用 Live Server 启动应用开发中频繁测试能尽早发现问题。VS Code 的 Live Server 扩展会在你每次保存文件时自动刷新浏览器显著提升迭代效率。安装后通过快捷键Ctrl-Shift-PmacOS 为Cmd-Shift-P打开命令面板输入并执行「Live Server: Open with Live Server」。它会为项目启动一个本地开发服务器保存文件时自动刷新浏览器通过本地 URL通常是localhost:5500伺服文件。之后在浏览器中打开http://localhost:5500即可看到页面——接下来为它注入功能。构建用户界面搭建游戏舞台如果把游戏比作飞船控制台我们需要把玩家所需的一切摆在正确的位置。先梳理游戏必需的四个 UI 元素UI 元素用途HTML 元素名言展示区显示待输入文本p idquote消息区域显示状态与成功提示p idmessage文本输入框玩家在此输入名言input idtyped-value开始按钮启动游戏button idstart每个元素都需要唯一 ID 供 JavaScript 定位。新建index.html并写入!-- index.html -- html head titleTyping game/title link relstylesheet hrefstyle.css /head body h1Typing game!/h1 pPractice your typing skills with a quote from Sherlock Holmes. Click **start** to begin!/p p idquote/p !-- 展示名言 -- p idmessage/p !-- 展示状态消息 -- div input typetext aria-labelcurrent word idtyped-value / !-- 打字输入框 -- button typebutton idstartStart/button !-- 启动游戏 -- /div script srcscript.js/script /body /html这段 HTML 结构的要点在head中引入CSS 样式表为玩家提供清晰的标题与操作说明用带特定 ID 的占位段落承载动态内容输入框带aria-label无障碍属性提供开始按钮触发游戏把 JavaScript 放在body末尾以优化加载性能。用 CSS 提供即时视觉反馈早在 1980 年代研究者就发现即时视觉反馈能大幅提升用户表现并降低出错率——这正是我们要达成的目标。玩家必须一眼看清当前该打哪个词、打错了又该立刻看到。新建style.css/* style.css */ .highlight { background-color: yellow; } .error { background-color: lightcoral; border: red; }这两个类的职责用黄色背景高亮当前单词提供清晰视觉引导用浅珊瑚红背景标记输入错误在不打断打字节奏的前提下即时反馈采用对比色兼顾无障碍与清晰传达。样式可以自由发挥换一种字体、给标题上色、调整元素尺寸让页面更赏心悦目。JavaScript 核心实现给游戏装上发动机HTML 与 CSS 就绪后游戏还只是一辆没有发动机的漂亮汽车。下面按「常量 → 开始逻辑 → 打字逻辑」三步走循序渐进地组装。新建script.js。第一步定义常量与 DOM 引用开工前先把所有「资源」备齐——正如 NASA 任务控制中心在发射前准备好全部监控系统这样可以避免之后反复查找、也防止拼写错误。需要初始化的数据如下数据类型用途示例名言数组存储游戏中所有可选名言[名言 1, 名言 2, ...]单词数组将当前名言拆分为单词[When, you, have, ...]单词索引跟踪玩家正在输入的单词0, 1, 2, 3...开始时间计算得分所需的耗时Date.now()同时需要保存三个 UI 元素的引用元素ID用途文本输入框typed-value玩家输入的位置名言展示区quote展示待输入名言消息区域message展示状态更新// script.js —— 顶部 // 所有名言 const quotes [ When you have eliminated the impossible, whatever remains, however improbable, must be the truth., There is nothing more deceptive than an obvious fact., I ought to know by this time that when a fact appears to be opposed to a long train of deductions it invariably proves to be capable of bearing some other interpretation., I never make exceptions. An exception disproves the rule., What one man can invent another can discover., Nothing clears up a case so much as stating it to another person., Education never ends, Watson. It is a series of lessons, with the greatest for the last., ]; // 存储单词列表与玩家当前输入单词的索引 let words []; let wordIndex 0; // 开始时间 let startTime Date.now(); // 页面元素 const quoteElement document.getElementById(quote); const messageElement document.getElementById(message); const typedValueElement document.getElementById(typed-value);这段初始化代码的设计意图用const存储名言数组因为名言本身不会变化用let声明跟踪变量因为它们会在游戏过程中更新用document.getElementById()一次性捕获 DOM 引用方便后续高效访问使用清晰、描述性的变量名为全部游戏功能打下基础将相关数据与元素逻辑分组便于代码维护。扩展练习向quotes数组中追加更多名言。专业提示document.getElementById()随时可以重新获取元素但既然要反复引用它们不如用常量封装以避免字符串字面量的拼写错误。这也是后续使用 Vue.js、React 等框架统一管理 DOM 引用的思想雏形。这样做的优势包括多次引用时防止拼写错误、描述性常量名提升可读性、获得更好的 IDE 自动补全与错误检查、以及当元素 ID 变更时更易重构。第二步添加开始逻辑 —— 你的第一个事件监听器玩家可能在任意时刻点击 Start——也许立即、也许喝完咖啡之后——但点击发生时游戏必须瞬间苏醒。因此我们需要随机选一条名言、重置 UI、建立单词与计时的跟踪状态。// script.js —— 末尾追加 document.getElementById(start).addEventListener(click, () { // 随机获取一条名言 const quoteIndex Math.floor(Math.random() * quotes.length); const quote quotes[quoteIndex]; // 将名言拆分为单词数组 words quote.split( ); // 重置单词索引 wordIndex 0; // UI 更新 // 创建 span 元素数组以便为每个单词单独设置 class const spanWords words.map(function(word) { return span${word} /span}); // 拼接为字符串并写入名言展示区的 innerHTML quoteElement.innerHTML spanWords.join(); // 高亮第一个单词 quoteElement.childNodes[0].className highlight; // 清空之前的消息 messageElement.innerText ; // 设置输入框 typedValueElement.value ; // 清空输入框 typedValueElement.focus(); // 聚焦玩家可直接输入 // 启动计时 startTime new Date().getTime(); });逐段拆解这段逻辑 单词跟踪初始化用Math.floor()Math.random()随机挑选名言以保证每局不同用split( )把名言拆成单词数组把wordIndex重置为 0玩家从第一个单词开始为新一轮游戏准备好状态。 UI 渲染用map()把每个单词包进span以便单独设样式join()拼成字符串后一次性写入innerHTML高效 DOM 更新通过添加highlight类高亮第一个单词清空上一局遗留的消息。⌨️ 输入框准备清空旧文本focus()让光标自动落入输入框玩家可立即开打。⏱️ 计时启动用new Date().getTime()记录当前时间戳为之后精确计算打字耗时做好准备。第三步添加打字逻辑 —— 游戏的心脏每敲下一个字符代码都要判断「打对了没有」、给出反馈、并决定下一步。这类似 1970 年代 WordStar 等早期文字处理器对打字者的实时反馈。代码采用「瀑布式」判断从最具体到最一般的条件逐级下探。// script.js —— 末尾追加 typedValueElement.addEventListener(input, () { // 获取当前目标单词 const currentWord words[wordIndex]; // 获取当前已输入的值 const typedValue typedValueElement.value; if (typedValue currentWord wordIndex words.length - 1) { // 句子结束 // 显示成功信息 const elapsedTime new Date().getTime() - startTime; const message CONGRATULATIONS! You finished in ${elapsedTime / 1000} seconds.; messageElement.innerText message; } else if (typedValue.endsWith( ) typedValue.trim() currentWord) { // 单词结束 // 清空输入框以输入新单词 typedValueElement.value ; // 前进到下一个单词 wordIndex; // 重置名言中所有单词的 class for (const wordElement of quoteElement.childNodes) { wordElement.className ; } // 高亮新单词 quoteElement.childNodes[wordIndex].className highlight; } else if (currentWord.startsWith(typedValue)) { // 目前输入正确 typedValueElement.className ; } else { // 错误状态 typedValueElement.className error; } });打字逻辑的判断流程 场景一名言完整收尾—— 判断输入值等于当前单词且处于最后一个单词用当前时间减去开始时间得到elapsedTime除以 1000 把毫秒换算成秒展示含耗时的祝贺消息。✅ 场景二单词完整推进—— 以「输入以空格结尾」识别单词完成用trim()校验去掉空格后与目标单词完全一致清空输入框迎接下一词wordIndex推进索引先清除全部单词的 class 再高亮新单词。 场景三打字进行中正确—— 用currentWord.startsWith(typedValue)判断当前输入是否为目标单词的前缀若正确则移除错误样式允许无中断地继续输入。❌ 场景四错误状态—— 输入与预期单词开头不匹配时触发为输入框添加error类给出即时视觉反馈帮助玩家快速定位并纠正。结合官方 Solution 源码从教学版到工程化 ES6仓库中的 4-typing-game/solution/index.js 提供了同一游戏的教学版工程化演进非常适合对照学习。它在保持全部核心机制不变的前提下做了几处值得借鉴的升级1. DOM 选择统一改用querySelectorsolution/index.js并把 Start 按钮也纳入引用替代教学版中document.getElementById(start)的临时查询。2. 把可复用逻辑抽成具名工具函数getRandomQuote()封装随机选名言solution/index.jsrenderQuote()把名言渲染为带高亮的 span 列表solution/index.jshighlightWord(index)用classList.toggle优雅地切换当前单词的高亮solution/index.js。整体事件处理也收敛为startGame与handleTyping两个具名处理器solution/index.js替代教学版的两段匿名回调。3. 消息系统对象化messages.success / error / startsolution/index.js把散落的模板字符串集中管理success回调还通过toFixed(2)把秒数格式化为两位小数。4. 状态收尾更健壮完成名言后执行typedValueElement.disabled truesolution/index.js禁用输入框防止玩家在游戏结束后继续输入——这正是原文档 Challenge 章节中「输入控制」与「UI 状态管理」两项任务的标准实现。配套的 solution/index.html 展示了更完整的页面引入 Font Awesome 图标、为输入框添加label与placeholder、按钮内嵌图标solution/index.css 则把教学版仅有的两个类扩展为一套完整视觉体系——渐变背景、圆角卡片式名言区、按钮悬停动画与移动端响应式布局。你可以在原教学版基础上按此思路逐步打磨自己的版本。测试你的应用点击start开始输入验证游戏是否按预期工作。如果第一遍不完美也完全正常——资深开发者同样会经常遇到 bug这正是开发过程的一部分。需要验证的测试点点击 Start 会展示一条随机名言输入时当前单词被正确高亮输入错误时出现错误样式完成一个单词后高亮正确前移完成整条名言后显示带耗时的完成消息。常见调试技巧按 F12 打开浏览器控制台检查 JavaScript 报错确认所有文件名大小写完全一致文件名区分大小写确保Live Server 正在运行且能正常刷新多试几条名言验证随机选取逻辑。扩展挑战把游戏推向更高水准原文档提供了两条进阶路径。首先是用 Agent 模式实现的GitHub Copilot Agent Challenge为游戏引入自适应难度系统——跟踪玩家的打字速度WPM与准确率在「简单简短名言/ 中等现有名言/ 困难含标点的复杂名言」三档间自动切换在 UI 中展示当前难度与统计信息通过连击计数器在连续 3 次良好表现后提升难度并用颜色、动画给出难度变化的视觉反馈同时保证 ARIA 无障碍标签与完善的错误处理。其次是经典的Challenge 功能清单功能描述你会练习的技能输入控制完成时禁用input事件监听器点击按钮时重新启用事件管理与状态控制UI 状态管理玩家完成名言后禁用输入框DOM 属性操作模态对话框用模态弹窗展示成功消息高级 UI 模式与无障碍最高分系统用localStorage持久化最高分浏览器存储 API 与数据持久化实现提示研究localStorage.setItem()与localStorage.getItem()实现持久化练习动态添加/移除事件监听器探索 HTML 原生dialog元素或 CSS 模态模式在禁用/启用表单控件时始终考虑无障碍体验这也与 Solution 中disabled true的收尾处理一脉相承。课后任务打造你的专属键盘游戏本课的课后作业是创建一个新的键盘游戏英文原版见 4-typing-game/typing-game/assignment.md设计并实现一个使用键盘事件完成特定任务的小游戏——可以是另一款打字游戏、按键作画的像素画应用、用方向键控制的街机小游戏或任何你能想到的创意。要求至少包含3 个以上键盘事件监听器、即时的视觉反馈、计分/关卡/进度等游戏逻辑、以及清晰的说明与直观的控制。文中还提供了节奏游戏、像素画生成器、贪吃蛇、音乐合成器等 7 个灵感方向与评分标准可作为自我检验的参照。总结至此你已用事件驱动编程从零构建了一个真正可运行、可计时的打字游戏。事件驱动编程正是让 Web 保持鲜活与响应的根本——每当你看到下拉菜单、输入即校验的表单或响应点击的游戏时你现在都理解了其背后的魔法。你不仅在学习写代码更在学习创造直觉化、有吸引力的数字体验。回顾一下最有成就感的一刻、对比开始前的自己、思考还能加上哪些让游戏独一无二的功能——然后把事件处理的思路应用到下一个项目中去吧。【免费下载链接】Web-Dev-For-Beginners24 Lessons, 12 Weeks, Get Started as a Web Developer项目地址: https://gitcode.com/GitHub_Trending/we/Web-Dev-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询