JS+H5打字练习器
实现功能
1.导入.TXT文件到打字练习内容(部分浏览器可能出于安全问题限制了这一步操作)
2.输入文本到打字练习内(弹出输入框,将要练习的内容输入至输入框)
3. 开始练习,并根据正误在打字练习内容文本上修改颜色(某个字正确显示绿色,某个字错误,显示红色,某个字没有打显示灰色)
4.开始练习、结束练习,全部输入完成后自动结束练习,也可提前手动结束练习,结束练习后弹窗用显示时和正确率。(区别在于一个全部输入完成且全部正确,一个提前结束无其他条件)
效果图


分析
HTML 结构解析
- 根元素:
<!DOCTYPE html>声明文档类型为HTML。 html元素:包含整个页面的内容,并设置语言为中文(lang="zh-CN")。head元素:包含页面的元数据,如字符集(charset="UTF-8")、视口设置(viewport)和标题(<title>)。style元素:包含页面的CSS样式。- 设置页面背景颜色、字体、布局样式等。
body元素:包含页面的可见内容。- 使用Flexbox布局使内容居中。
.container类:包含文本输入框和按钮,并设置样式。.buttons类:包含一组按钮,并设置布局样式。.text-to-type类:包含待输入的文本,并设置样式。input元素:一个文本输入框,用于用户输入。
JavaScript 解析
-
变量声明:
textToType:获取待输入文本的DOM元素。inputText:获取用户输入文本的DOM元素。importTextBtn、addTextBtn、startPracticeBtn、endPracticeBtn:获取按钮的DOM元素。originalText:存储原始待输入的文本。startTime:存储开始练习的时间。alertCount:存储弹窗次数。correctCount:存储正确的字符数。
-
inputText输入事件监听器:- 当用户在输入框中输入时,会触发此事件。
- 获取用户当前输入的文本。
- 初始化一个空字符串
updatedText用于构建更新后的文本。 - 如果
startTime已设置,遍历原始文本和用户输入的文本:- 如果字符匹配,将字符标记为
correct。 - 如果字符不匹配,将字符标记为
wrong。
- 如果字符匹配,将字符标记为
- 更新
textToType的HTML内容。 - 如果用户输入的文本与原始文本完全匹配,计算总用时和正确率,并通过弹窗显示结果。
- 重置输入框和
startTime。
-
importTextBtn点击事件监听器:- 创建一个文件输入元素,允许用户选择
.txt文件。 - 当文件被选中后,使用
FileReader读取文件内容。 - 读取完成后,将文本内容赋值给
originalText并更新textToType。
- 创建一个文件输入元素,允许用户选择
-
addTextBtn点击事件监听器:- 弹出一个输入框让用户输入文本。
- 如果用户输入了文本,将其赋值给
originalText并更新textToType。
-
startPracticeBtn点击事件监听器:- 设置
startTime为当前时间。 - 清空输入框。
- 更新
textToType的HTML内容为原始文本。
- 设置
-
endPracticeBtn点击事件监听器:- 如果
startTime已设置,计算总用时和正确率,并通过弹窗显示结果。 - 重置
startTime和输入框。
- 如果
完成源代码
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>打字练习</title><style>body {font-family: Arial, sans-serif;background-color: #f0f0f0;display: flex;justify-content: center;align-items: center;height: 100vh;margin: 0;}.container {background-color: white;padding: 20px;border-radius: 15px;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);max-width: 600px;width: 100%;text-align: center;}.buttons {display: flex;justify-content: space-around;margin-bottom: 20px;}.buttons button {background-color: black;color: white;border: none;border-radius: 5px;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);padding: 10px 20px;cursor: pointer;font-size: 14px;}.text-to-type {color: gray;margin-bottom: 20px;font-size: 20px;}.text-to-type span.correct {color: green;}.text-to-type span.wrong {color: red;}input[type="text"] {width: 100%;padding: 10px;border-radius: 5px;border: 1px solid #ccc;font-size: 18px;}</style>
</head>
<body><div class="container"><div class="buttons"><button id="importText">导入文本</button><button id="addText">添加文本</button><button id="startPractice">开始练习</button><button id="endPractice">结束练习</button></div><div class="text-to-type" id="textToType">这是一个打字练习的例子</div><input type="text" id="inputText" placeholder="开始打字..." /></div><script>const textToType = document.getElementById('textToType');const inputText = document.getElementById('inputText');const importTextBtn = document.getElementById('importText');const addTextBtn = document.getElementById('addText');const startPracticeBtn = document.getElementById('startPractice');const endPracticeBtn = document.getElementById('endPractice');let originalText = textToType.innerText;let startTime = null;let alertCount = 0;let correctCount = 0;inputText.addEventListener('input', () => {const typedText = inputText.value;let updatedText = '';correctCount = 0;if (startTime) {for (let i = 0; i < originalText.length; i++) {if (i < typedText.length) {if (typedText[i] === originalText[i]) {updatedText += `<span class="correct">${originalText[i]}</span>`;correctCount++;} else {updatedText += `<span class="wrong">${originalText[i]}</span>`;}} else {updatedText += originalText[i];}}textToType.innerHTML = updatedText;}if (typedText === originalText && startTime) {const endTime = new Date();const timeTaken = ((endTime - startTime) / 1000).toFixed(2);const accuracy = ((correctCount / originalText.length) * 100).toFixed(2);alert(`总用时间: ${timeTaken} 秒\n正确率: ${accuracy}%`);alertCount++;if (alertCount < 3) {alert(`这是第 ${alertCount} 次弹窗`);}inputText.value = '';startTime = null;}});importTextBtn.addEventListener('click', () => {const fileInput = document.createElement('input');fileInput.type = 'file';fileInput.accept = '.txt';fileInput.onchange = e => {const file = e.target.files[0];const reader = new FileReader();reader.onload = event => {originalText = event.target.result.trim();textToType.innerText = originalText;};reader.readAsText(file);};fileInput.click();});addTextBtn.addEventListener('click', () => {const userInput = prompt('请输入要练习的文本:');if (userInput) {originalText = userInput.trim();textToType.innerText = originalText;}});startPracticeBtn.addEventListener('click', () => {startTime = new Date();inputText.value = '';textToType.innerHTML = originalText;});endPracticeBtn.addEventListener('click', () => {if (startTime) {const endTime = new Date();const timeTaken = ((endTime - startTime) / 1000).toFixed(2);const accuracy = ((correctCount / originalText.length) * 100).toFixed(2);alert(`练习结束\n总用时间: ${timeTaken} 秒\n正确率: ${accuracy}%`);startTime = null;inputText.value = '';} else {alert('请先开始练习!');}});</script>
</body>
</html>
相关文章:
JS+H5打字练习器
实现功能 1.导入.TXT文件到打字练习内容(部分浏览器可能出于安全问题限制了这一步操作) 2.输入文本到打字练习内(弹出输入框,将要练习的内容输入至输入框) 3. 开始练习,并根据正误在打字练习内容文本上修…...
windows系统关闭开机自检硬盘
效果: 注册表关闭开机硬盘自检,你可以按照以下步骤操作: 打开注册表编辑器: 按 Win R 键打开“运行”对话框。输入 regedit 并按回车,打开注册表编辑器。 定位到自检相关的键: 依次展开以下路径&#x…...
【多线程开发 5】实践使用Lock和Condition
Lock和Condition Lock 线程之间同步或者竞争都需要锁这类结构,一般我们都会用Object的wait和signal搭配synchronized关键字进行多线程开发,但是很多时候会造成死锁的现象,这是因为synchroniezd无法破坏死锁的产生条件,但是Lock接…...
2.4-结构化并发:协程的结构化异常管理
文章目录 协程结构化异常流程协程结构化异常流程和取消流程的区别子协程异常为什么要连带取消父协程? CoroutineExceptionHandler异常协程异常的最后一道拦截:CoroutineExceptionHandlerCoroutineExceptionHandler 为什么只能设置给最外层协程才有效&…...
Android 12.0 debug版本打开OEM解锁开关功能实现
通常为了方便push在debug版本会采用如下命令 adb root adb disable-verity 提示: Device is locked. Please unlock the device first. 查找日志可以发现system/core/set-verity-state/set-verity-state.cpp文件中is_avb_device_locked方法里 这个获取ro.boot…...
linux用户组练习
准备工作 [rootlocalhost ~]# watch -n 1 tail -n 5 /etc/group使用watch 动态监控 1.建立用户组 shengcan,其id 为2000 2.建立用户组 caiwu,其id 为 2001 3.足建立用户组 jishu,其id 为 2002 4.建立用户lee,指定其主组id为sh…...
[Docker][Docker Container]详细讲解
目录 1.什么是容器?2.容器命令1.docker creatre2.docker run3.docker ps4.docker logs5.docker attach6.docker exec7.docker start8.docker stop9.docker restart10.docker kill11.docker top12.docker stats13.docker container inspect14.docker port15.docker c…...
塑造美好心灵,激发创造活力|第三届瓷艺中华“陶溪川杯”儿童青少年陶瓷作品展开展
第三届瓷艺中华“陶溪川杯”儿童青少年陶瓷作品展 展览现场 由中央美术学院、景德镇陶瓷大学、景德镇陶文旅控股集团共同主办,由中国非物质文化遗产保护协会陶瓷分会、中国文化艺术发展促进会陶瓷专业委员会、中央美术学院陶瓷艺术研究院、中央美术学院少儿美术教…...
鸿蒙开发刷新单个item会闪一下处理
鸿蒙开发刷新单个item会闪一下 首先我用的是懒加载方式,改变某位数据后我调listener.onDataChange(index),发现item的改动是变了,但是item也闪了一下。 先分析为什么item会闪一下 其他是因为item上有图片,加载的网络图。你onDataChange(index)时,它会重新加载这一item,…...
您需要了解的有关 5G 的一切。
转载 https://www.qualcomm.com/5g/what-is-5g 在这里,您可以找到 5G 技术的解释——5G 的工作原理、5G 的重要性以及它如何改变世界连接和沟通的方式。在 Qualcomm,我们发明了使 5G 成为可能的根本性突破。 问:什么是 5G? 答&…...
【redis】初识redis入门,基础部署以及介绍
本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》:python零基础入门学习 《python运维脚本》: python运维脚本实践 《shell》:shell学习 《terraform》持续更新中:terraform_Aws学习零基础入门到最佳实战 《k8…...
数据库基础 -- 数据库约束
数据库基础 – 数据库约束 1.约束 1.1 概念 约束是用于强制数据库中数据 完整性 和 一致性 的规则。它们定义了对表中数据的限制,确保数据的有效性和正确性,实际上就是表中数据的限制条件。 1.2 分类 1.2.1 完整性约束 主键约束(Primary Key Const…...
U盘文件或目录损坏无法读取?专业恢复策略全解析
U盘困境:文件目录的隐形危机 在日常的数字生活中,U盘作为便捷的数据存储与传输工具,扮演着至关重要的角色。然而,当U盘中的文件或目录突然遭遇损坏,导致无法被正常读取时,这无疑给用户带来了极大的困扰。这…...
dpdk实现udp协议栈
使用DPDK实现UDP用户态协议栈,实现流程中包括: 三类线程 1、收发包线程 2、用户态协议栈线程 3、udp服务端线程 两类缓冲区: 1、协议栈收包缓冲区和协议栈发包缓冲区 2、udp收包缓冲区和udp发包缓冲区 协议栈缓冲区中存储的数据是str…...
Shell编程——基础语法(2)和 Shell流程控制
文章目录 基础语法(2)echo命令read命令printf命令test命令 Shell流程控制if-else语句for 循环while 语句until 循环case ... esac跳出循环 基础语法(2) echo命令 Shell 的 echo 指令与 PHP 的 echo 指令类似,都是用于…...
Python基础教程(二)字符串和函数
6.字符串 6.1 字符串的表示方式 6.1.1 普通字符串 普通字符串指用单引号()或双引号(”")括起来的字符串。例如:Hello或"Hello" >>> Hello Hello >>> "Hello" Hello >>> s\u0048\u0065\u006c\u006c\u006f >>> …...
智算新风向丨趋动科技获中国信通院泰尔实验室首张智算资源池化能力泰尔测评证书
近日,趋动科技“OrionX AI算力资源池化软件”经中国泰尔实验室依据《FG-Z14-0172-01智算资源池化平台测试方案》评估测试,获得智算资源池化能力泰尔测评证书,成为该领域首个完成此评价的产品。 图1.OrionX通过智算资源池化平台评测 随着AI大…...
计算机基础(Windows 10+Office 2016)教程 —— 第4章 计算机网络与Internet(上)
第4章 计算机网络与Internet 4.1 计算机网络概述4.1.1 计算机网络的定义4.1.2 计算机网络的发展4.1.3 计算机网络的功能4.1.4 计算机网络体系结构和TCP/IP 参考模型 4.2 计算机网络的组成和分类4.2.1 计算机网络的组成4.2.2 计算机网络的分类 4.3 网络传输介质和通信设备4.3.1 …...
MES系统在数字化转型中的核心作用与影响
数字化转型是企业利用数字技术改变其业务模式、运营方式、组织结构、产品服务等方面的过程,旨在提高效率、降低成本、增强竞争力并实现可持续发展。数字化转型涉及多个层面,主要包括以下几个方面: 数字化转型转什么 转战略:由构…...
装修施工注意事项
1 地漏保护 咋墙拆改时,一定要用保护盖把所有的地漏下水管道都拧紧 2 卫生间防水做完,必须要先用水泥砂浆做好保护层再贴,不然后续施工,不小心破坏防水层,以后漏水后悔都晚了。 3 入户门口处,一定要用…...
互联网大厂 Java 面试实战:一次“高并发系统追问”下的真实对话
在大多数 Java 面试中,真正拉开差距的从来不是“你会多少知识点”,而是当系统出现问题时,你是否知道该怎么扛。很多候选人熟悉各种八股文,但一旦进入场景题就会卡住。下面通过一场更贴近真实大厂风格的面试,对话式还原…...
GNSS说第(八)讲---自适应动态导航定位(八)---抗差估计在复杂环境下的应用实践
1. 抗差估计:GNSS定位的"防弹衣" 想象一下你在高楼林立的城市峡谷中打开手机导航,信号时断时续,定位图标像喝醉酒一样到处乱飘——这就是典型的多路径干扰场景。传统最小二乘法就像用普通尺子测量扭曲的橡皮筋,单个异常…...
告别低效写作:盘点2026年标杆级的AI论文网站
一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文网站,覆盖选题构思、文献整理、内容生成、格式排版全流程,帮你高效搞定论文写作。 一、全流程王者:一站式搞定论文全链路(一天定稿首选ÿ…...
pyNastran:打破工程仿真壁垒的开源Python解决方案
pyNastran:打破工程仿真壁垒的开源Python解决方案 【免费下载链接】pyNastran A Python-based interface tool for Nastrans file formats 项目地址: https://gitcode.com/gh_mirrors/py/pyNastran 在航空航天、汽车制造等高端制造领域,有限元分析…...
2026最新Java金三银四面试参考指南公开!
想必有很多小伙伴这会已经在为金三银四面试跳槽做准备了。临近面试肯定是要想办法提升自己的面试能力,这个时候如果还去一昧地提升自己的代码能力对面试是毫无帮助的。大多数人在面试的时候都会遇到以下几种情况(大家可以看看自己中了几个)&a…...
手把手教你用4090D单卡24G显存本地跑DeepSeek-R1:KTransformers保姆级安装与避坑指南
手把手教你用4090D单卡24G显存本地跑DeepSeek-R1:KTransformers保姆级安装与避坑指南 最近在折腾大模型本地部署的朋友们,应该都听说过DeepSeek-R1这个671B参数的"巨无霸"。传统认知里,这种规模的模型至少需要专业级GPU集群才能跑起…...
2026 机器人行业发展前景与 AI 获客方案深度解析
引言:机器人行业的爆发式增长与获客挑战2026 年 3 月,全球机器人行业正处于爆发前夜。数据显示,2026 年全球机器人市场规模预计将达到 4000 亿元,较 2025 年增长 25%(数据来自网络)。随着具身智能技术的加速…...
无限级数求和的Java实现与数学分析
本文旨在详细说明如何使用Java精确计算特定形式的无限级数 S -(2x)^2/2! (2x)^4/4! - (2x)^6/6! ... 在指定区间 [0.1, 1.5] 内部和。我们将深入分析等级数的数学性质,推导其闭合形式,并在此基础上纠正原始Java代码…...
脑波货币化:公司用我的焦虑情绪炒期货
一、软件测试工程师:焦虑的“完美生产者”在持续集成、敏捷交付的现代开发流程中,软件测试从业者长期处于多重压力夹击之下:精确性高压:对缺陷零容忍的行业标准,使每一次测试执行如同走钢丝技术迭代焦虑:AI…...
Python+Mediamtx实战:5分钟搞定WebRTC视频流帧捕获(附完整代码)
PythonMediamtx实战:5分钟搞定WebRTC视频流帧捕获(附完整代码) 在实时视频处理领域,WebRTC技术因其低延迟和点对点传输特性而备受青睐。本文将带你快速搭建一个基于Mediamtx流媒体服务器和Python的WebRTC视频帧捕获系统࿰…...
