Web-Dev-For-Beginners 实战:用事件驱动编程(Event-Driven Programming)构建一个打字速度游戏
2026/9/11 2:45:59 网站建设 项目流程

Web-Dev-For-Beginners 实战:用事件驱动编程(Event-Driven Programming)构建一个打字速度游戏

【免费下载链接】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 章(4-typing-game),完整讲解如何以事件驱动编程为核心思想,从零构建一个基于福尔摩斯名言的打字速度游戏。通过本指南,你将掌握addEventListener事件监听机制、游戏状态管理、实时输入校验与视觉反馈等关键技术,并能结合仓库中的官方源码(教学版 与 Solution 实现)理解从教学代码到工程化实现的演进路径。

课程定位:为什么选择打字游戏来学习事件驱动编程

打字速度是每一位开发者都拥有却极少被刻意训练的"隐藏超能力"——从大脑到代码编辑器的通道越快,创造力流动就越顺畅。而 Web-Dev-For-Beginners 课程(24 课、12 周、面向 Web 开发初学者)在第 4 章选择用"打字游戏"这一载体,正是因为它天然依赖键盘输入事件,是理解浏览器与 JavaScript 之间"对话"机制的最佳场景。

这门课程的核心目标,是让你理解互动网页的底层运行逻辑:浏览器在用户每次点击、键入、移动鼠标时,都会向 JavaScript 代码发送一条条称为event(事件)的"小消息",而开发者通过编写事件监听器来决定如何响应。当你完成本项目的学习后,你将亲手得到一个能够实时跟踪输入速度与准确率、并显示完成耗时的可玩打字游戏——同时理解驱动一切互动网站的核心原理。

事件驱动编程:从"顺序执行"到"等待与响应"

什么是事件

传统编程按"从上到下"的顺序执行代码,如同照着菜谱做菜。但 Web 应用面临一个本质不确定性:我们永远不知道用户何时会点击按钮或开始输入——可能立即点击,可能五分钟后,也可能永远不点。这种不可预测性要求我们换一种思路写代码:不是主动执行,而是写下一段"耐心等待某事发生"的代码,就像 1800 年代的电报员守在机器旁、时刻准备响应线上传来的消息。

简单来说,事件就是"发生的事情":点击按钮是事件,键入一个字母是事件,移动鼠标也是事件。事件驱动编程让我们把代码设置为"监听 + 响应"模式。

事件监听器:为你的代码装上"门铃"

我们通过创建名为event listener(事件监听器)的特殊函数来实现监听与响应。可以把事件监听器想象成代码的门铃:

  • 装上门铃:调用addEventListener()
  • 告诉它听什么声音:传入事件名,如'click''input'
  • 指定门铃响时做什么:传入自定义回调函数

事件监听器的四大特性:

  • 监听特定的用户动作(点击、按键、鼠标移动)
  • 执行事件发生时你编写的自定义代码
  • 响应用户交互,创造无缝的实时体验
  • 处理同一元素上的多个事件(通过挂载不同的监听器)

说明:创建事件监听器的方式有很多,可以使用匿名函数或具名函数,也可以使用onclick这类快捷属性。本课程聚焦于addEventListener()+ 匿名函数这一组合,因为它是 Web 开发者最常用、也最灵活的方式——它对所有事件通用,且事件名可作为参数动态传入。

常用事件一览

浏览器提供了数十种可监听的事件(用户几乎任何操作都会触发事件),但大多数交互应用只依赖少量核心事件。下面是课程列出的事件表(含本项目用到的两个事件):

事件描述常见使用场景
click用户点击了某元素按钮、链接、交互元素
contextmenu用户点击鼠标右键自定义右键菜单
select用户选中了部分文本文本编辑、复制操作
input用户输入了文本表单校验、实时搜索

这些事件在用户与页面元素交互时触发,通过事件对象提供详细信息,让我们得以创建响应式交互应用,并在不同浏览器与设备上保持一致行为

游戏设计:功能拆解与流程建模

本项目游戏使用福尔摩斯(Sherlock Holmes)的名言作为输入素材,整体功能占比大致为:实时反馈 25%、性能追踪 20%、交互式 UI 20%、计时系统 15%、引语管理 10%、结果展示 10%。

游戏的核心流程如下:

  1. 玩家点击Start按钮 → 随机显示一条福尔摩斯名言
  2. 玩家在文本框逐词输入
  3. 当前词输入正确 → 高亮下一个词;输入有误 → 显示错误样式
  4. 整个引语完成 → 显示包含耗时的成功消息

基于此,游戏需要具备以下能力:

  • 启动:玩家点击开始按钮后显示随机引语
  • 追踪:实时按词追踪玩家的输入进度
  • 高亮:高亮当前应输入的词,引导玩家注意力
  • 反馈:输入错误时立即给出视觉反馈
  • 结算:引语完成时计算并显示总耗时

项目搭建:文件结构与开发环境

保持整洁的文件结构是专业开发的第一步。本项目只需经典"三件套"文件:

  • index.html—— 页面结构与内容
  • script.js—— 全部游戏逻辑与事件监听器
  • style.css—— 视觉外观与样式

在终端中创建项目目录:

# Linux 或 macOS mkdir typing-game && cd typing-game # Windows md typing-game && cd typing-game

然后使用 VS Code 打开并新建上述三个文件:

code .

启动开发服务器:推荐安装 VS Code 的 Live Server 扩展,它会在本地托管应用,并在每次保存文件时自动刷新浏览器。安装后按Ctrl-Shift-P(macOS 为Cmd-Shift-P)打开命令面板,输入并执行"Live Server: Open with Live Server",然后在浏览器中访问https://localhost:5500即可看到页面。迭代式开发能让你尽早发现问题、实时看到进展。

用户界面:HTML 结构

游戏界面需要四个关键 UI 元素:

UI 元素用途HTML 元素
引语展示区显示待输入的文本<p id="quote">
消息区显示状态与成功消息<p id="message">
文本输入框玩家输入引语<input id="typed-value">
开始按钮开始游戏<button id="start">

每个元素都需要唯一 ID 供 JavaScript 定位。创建index.html并添加以下代码:

<html> <head> <title>Typing game</title> <link rel="stylesheet" href="style.css"> </head> <body> <h1>Typing game!</h1> <p>Practice your typing skills with a quote from Sherlock Holmes. Click **start** to begin!</p> <p id="quote"></p> <!-- 显示引语 --> <p id="message"></p> <!-- 显示状态消息 --> <div> <input type="text" aria-label="current word" id="typed-value" /> <!-- 输入框 --> <button type="button" id="start">Start</button> <!-- 开始按钮 --> </div> <script src="script.js"></script> </body> </html>

该结构在<head>中链接 CSS 样式表;创建清晰的标题与操作说明;用带 ID 的占位段落承载动态内容;输入框带有aria-label无障碍属性;<script>放在页面底部以获得最佳加载性能。

视觉反馈:CSS 样式

视觉反馈自计算早期就被证明能显著提升用户表现、降低错误率。游戏需要让玩家立刻知道"该打哪个词"以及"是否打错了",因此定义两个简洁的样式类:

/* style.css 内容 */ .highlight { background-color: yellow; } .error { background-color: lightcoral; border: red; }
  • .highlight用黄色背景高亮当前应输入的词,提供清晰的视觉引导
  • .error用浅珊瑚色背景标识输入错误,在输入同时给出即时反馈
  • 对比色设计兼顾了无障碍与清晰沟通

提示:样式可以自由发挥——换一种字体、给标题上色、调整元素尺寸,让页面更美观。

游戏逻辑:JavaScript 实现

HTML 和 CSS 搭好了"车身",JavaScript 则是让一切运转的"引擎"。我们将按三个步骤循序渐进地实现。

第一步:常量与状态初始化

// 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 引用,后续高效复用
  • 使用具名常量避免重复书写字符串字面量造成拼写错误,还能获得 IDE 自动补全与重构支持

第二步:开始逻辑(click 事件)

当用户点击 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,便于单独设置样式 const spanWords = words.map(function(word) { return `<span>${word} </span>`}); 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 搭建:将每个单词包进<span>并拼接为字符串一次性写入innerHTML(高效更新 DOM);为第一个单词加上highlight类;清空上局消息。

输入框准备:清空残留文本并调用.focus()让玩家可以立刻开始输入。

计时初始化:用new Date().getTime()记录当前时间戳,为计算输入速度与完成耗时奠定基础。

第三步:打字逻辑(input 事件)

这是游戏的心脏。每一次键入字符,代码都会校验输入、给出反馈并决定下一步。实现采用瀑布式(waterfall)判断——从最具体到最一般的条件依次检查:

// script.js 末尾 typedValueElement.addEventListener('input', () => { // 获取当前应输入的单词 const currentWord = words[wordIndex]; // 获取当前输入值 const typedValue = typedValueElement.value; if (typedValue === currentWord && wordIndex === words.length - 1) { // 场景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) { // 场景2:当前单词完成(以空格结尾且去除空格后完全匹配) typedValueElement.value = ''; wordIndex++; // 清除所有单词的高亮样式 for (const wordElement of quoteElement.childNodes) { wordElement.className = ''; } // 高亮下一个单词 quoteElement.childNodes[wordIndex].className = 'highlight'; } else if (currentWord.startsWith(typedValue)) { // 场景3:到目前为止输入正确 typedValueElement.className = ''; } else { // 场景4:错误状态 typedValueElement.className = 'error'; } });

四个分支逐一解析:

🏁 场景 1 —— 整句完成:输入值完全匹配当前词当前词是最后一个词。用当前时间戳减去startTime得到耗时(毫秒),除以 1000 换算为秒,展示祝贺消息。

✅ 场景 2 —— 单词完成:输入以空格结尾且trim()后与当前词完全一致。清空输入框、wordIndex++前进到下一个词、清除全部高亮并为新词添加highlight类。

📝 场景 3 —— 输入进行中:当前词以已输入内容开头(startsWith),说明到目前为止正确,移除错误样式,允许继续输入。

❌ 场景 4 —— 错误状态:输入内容与预期不匹配,为输入框加上error类,立即给出红色视觉反馈。

源码对照:官方 Solution 的工程化重构

仓库中的完整参考实现位于 4-typing-game/solution/,采用现代 ES6+ 语法对教学版进行了重构,非常值得对照学习:

  • 工具函数拆分:index.js 将"随机取引语"(getRandomQuote)、"渲染引语为 span"(renderQuote)与"高亮当前词"(highlightWord)抽象为独立函数,逻辑更清晰、可复用性更强
  • 消息系统:用messages对象统一管理成功、错误、开始三类提示文案,替换散落的字符串拼接
  • classListAPI:用classList.toggle("highlight", i === index)classList.add/remove("error")取代直接赋值className,代码更健壮
  • 游戏结束处理:完成引语后通过typedValueElement.disabled = true禁用输入框(对应挑战列表中的"UI State Management")
  • UI 增强:index.html 引入 Font Awesome 图标、隐藏式 label(视觉隐藏但保留给屏幕阅读器)、日期时间显示;index.css 提供了渐变背景、卡片式引语展示、按钮悬停动画与移动端媒体查询等完整视觉方案

从教学版到 Solution 的演进,展示了同一套事件驱动逻辑在真实项目中的组织方式:状态集中管理、行为函数化、样式类原子化

测试与调试

点击 Start 开始游戏,运行效果可参考仓库中的演示动画 demo.gif。

测试清单

  • 点击 Start 是否显示随机引语
  • 输入时当前词是否正确高亮
  • 错误输入是否出现错误样式
  • 完成单词后高亮是否正确前进
  • 完成整条引语后是否显示含耗时的成功消息

常见调试技巧

  • 按 F12 打开浏览器控制台检查 JavaScript 报错
  • 确认所有文件名完全一致(区分大小写)
  • 确认 Live Server 正在运行并正常刷新
  • 多试几条引语验证随机选取逻辑

进阶挑战与课后作业

Challenge:为游戏增加高级功能

功能描述练习的技能
输入控制游戏完成后禁用input事件监听,点击按钮时重新启用事件管理与状态控制
UI 状态管理玩家完成引语后禁用文本框DOM 属性操作
模态对话框用模态对话框展示成功消息高级 UI 模式与无障碍
最高分系统localStorage持久化最高分浏览器存储 API 与数据持久化

实现提示:研究localStorage.setItem()localStorage.getItem();练习动态添加/移除事件监听器;探索 HTML dialog 元素或 CSS 模态模式;注意禁用/启用表单控件时的无障碍设计。

Copilot Agent 挑战:难度自适应系统

仓库还给出了一个基于 Agent 模式的扩展挑战:为打字游戏实现难度自适应系统——跟踪 WPM(每分钟字数)与准确率,在 Easy(简单引语)、Medium(当前引语)、Hard(带标点的复杂引语)三档间自动切换;UI 展示当前难度与玩家统计;连续 3 次良好表现后通过连击计数提升难度,并用颜色、动画给出难度变化反馈;同时保持 ARIA 无障碍标注。

课后作业:创建全新键盘游戏

作业要求(详见 assignment.md)设计一个使用键盘事件完成特定任务的小游戏,可以是另一种打字游戏、按键绘制像素的画板应用、方向键控制的街机游戏等。必须包含:

  • 事件监听器:响应至少 3 种不同的键盘事件
  • 视觉反馈:对用户输入立即给出视觉响应
  • 游戏逻辑:包含计分、关卡或进度机制
  • 用户界面:清晰的说明与直观的操作

作业提供了完整的评价量表(Rubric),从功能完整性、代码质量、用户体验、创意四个维度划分"优秀 / 达标 / 待改进"三档,可作为自评标准。

学习路径:从 5 分钟到专业级的能力成长

课程给出了清晰的进阶时间线(详见 课程概述 中的 Timeline 图):

  • Setup(10 分钟):搭建 HTML 基础、CSS 样式、创建 JS 文件
  • 用户界面(20 分钟):输入框、按钮、显示区与响应式布局
  • 事件处理(25 分钟):键盘/鼠标事件、实时反馈、状态管理
  • 游戏逻辑(30 分钟):引语生成、字符比对、准确率计算、计时器
  • 性能追踪(35 分钟):WPM 计算、错误追踪、进度可视化、结果展示
  • 打磨与增强(45 分钟):视觉反馈、音效、动画、无障碍特性
  • 高级功能(1 周):难度等级、排行榜、自定义引语、多人模式
  • 专业技能(1 个月):性能优化、代码架构、测试策略、部署模式

分阶段行动清单

5 分钟:打开浏览器控制台用addEventListener监听键盘事件;创建带输入框的简单 HTML 页面测试键入检测;练习用字符串比较对目标文本;用setTimeout理解定时函数。

1 小时:完成课后测验理解事件驱动编程;构建带单词校验的基础版打字游戏;添加正确/错误输入的视觉反馈;实现基于速度与准确率的简单计分系统;用 CSS 美化界面。

1 周:完成全功能打字游戏;添加不同词汇复杂度的难度等级;实现用户统计(WPM、长期准确率);加入音效与动画;适配触屏移动端;上线分享并收集反馈。

1 个月:构建多个探索不同交互模式的游戏;学习游戏循环、状态管理与性能优化;为开源游戏项目做贡献;掌握高级计时概念与平滑动画;建立展示各类交互应用的 portfolio;指导其他对游戏开发感兴趣的学习者。

完成后你将掌握的技能

  • 事件驱动编程:构建对输入实时响应的用户界面
  • 实时反馈:即时的视觉与性能更新
  • 性能测量:精确的计时与计分系统
  • 游戏状态管理:控制应用流程与用户体验
  • 交互设计:创造沉浸式的用户交互
  • 现代 Web API:善用浏览器能力实现丰富交互
  • 无障碍模式:面向所有用户的包容性设计

这些技能可直接迁移到网页应用(任意交互界面或仪表盘)、教育软件(学习平台与技能评估工具)、生产力工具(文本编辑器、IDE、协作软件)、游戏行业(浏览器游戏与互动娱乐)以及移动开发(触屏界面与手势处理)。

结语

事件驱动编程是让网页"活起来"的核心概念:下拉菜单、边输入边校验的表单、响应点击的游戏……这一切背后都是事件监听与响应的魔法。完成本项目后,你已经掌握了驱动每一款互动网站与应用的底层机制——你不仅在学习写代码,更在学着创造直观、引人入胜的用户体验。接下来,你完全有基础去探索高级游戏框架、实时多人系统或更复杂的交互应用了。

本课程模块由 Christopher Harrison 编写,隶属于 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

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询