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 入户门口处,一定要用…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
FFmpeg avformat_open_input函数分析
函数内部的总体流程如下: avformat_open_input 精简后的代码如下: int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...
