当前位置: 首页 > news >正文

JS+H5打字练习器

实现功能

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

效果图

在这里插入图片描述在这里插入图片描述

分析

HTML 结构解析

  1. 根元素<!DOCTYPE html> 声明文档类型为HTML。
  2. html 元素:包含整个页面的内容,并设置语言为中文(lang="zh-CN")。
  3. head 元素:包含页面的元数据,如字符集(charset="UTF-8")、视口设置(viewport)和标题(<title>)。
  4. style 元素:包含页面的CSS样式。
    • 设置页面背景颜色、字体、布局样式等。
  5. body 元素:包含页面的可见内容。
    • 使用Flexbox布局使内容居中。
  6. .container:包含文本输入框和按钮,并设置样式。
  7. .buttons:包含一组按钮,并设置布局样式。
  8. .text-to-type:包含待输入的文本,并设置样式。
  9. input 元素:一个文本输入框,用于用户输入。

JavaScript 解析

  1. 变量声明

    • textToType:获取待输入文本的DOM元素。
    • inputText:获取用户输入文本的DOM元素。
    • importTextBtnaddTextBtnstartPracticeBtnendPracticeBtn:获取按钮的DOM元素。
    • originalText:存储原始待输入的文本。
    • startTime:存储开始练习的时间。
    • alertCount:存储弹窗次数。
    • correctCount:存储正确的字符数。
  2. inputText 输入事件监听器

    • 当用户在输入框中输入时,会触发此事件。
    • 获取用户当前输入的文本。
    • 初始化一个空字符串updatedText用于构建更新后的文本。
    • 如果startTime已设置,遍历原始文本和用户输入的文本:
      • 如果字符匹配,将字符标记为correct
      • 如果字符不匹配,将字符标记为wrong
    • 更新textToType的HTML内容。
    • 如果用户输入的文本与原始文本完全匹配,计算总用时和正确率,并通过弹窗显示结果。
    • 重置输入框和startTime
  3. importTextBtn 点击事件监听器

    • 创建一个文件输入元素,允许用户选择.txt文件。
    • 当文件被选中后,使用FileReader读取文件内容。
    • 读取完成后,将文本内容赋值给originalText并更新textToType
  4. addTextBtn 点击事件监听器

    • 弹出一个输入框让用户输入文本。
    • 如果用户输入了文本,将其赋值给originalText并更新textToType
  5. startPracticeBtn 点击事件监听器

    • 设置startTime为当前时间。
    • 清空输入框。
    • 更新textToType的HTML内容为原始文本。
  6. 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文件到打字练习内容&#xff08;部分浏览器可能出于安全问题限制了这一步操作&#xff09; 2.输入文本到打字练习内&#xff08;弹出输入框&#xff0c;将要练习的内容输入至输入框&#xff09; 3. 开始练习&#xff0c;并根据正误在打字练习内容文本上修…...

windows系统关闭开机自检硬盘

效果&#xff1a; 注册表关闭开机硬盘自检&#xff0c;你可以按照以下步骤操作&#xff1a; 打开注册表编辑器&#xff1a; 按 Win R 键打开“运行”对话框。输入 regedit 并按回车&#xff0c;打开注册表编辑器。 定位到自检相关的键&#xff1a; 依次展开以下路径&#x…...

【多线程开发 5】实践使用Lock和Condition

Lock和Condition Lock 线程之间同步或者竞争都需要锁这类结构&#xff0c;一般我们都会用Object的wait和signal搭配synchronized关键字进行多线程开发&#xff0c;但是很多时候会造成死锁的现象&#xff0c;这是因为synchroniezd无法破坏死锁的产生条件&#xff0c;但是Lock接…...

2.4-结构化并发:协程的结构化异常管理

文章目录 协程结构化异常流程协程结构化异常流程和取消流程的区别子协程异常为什么要连带取消父协程&#xff1f; CoroutineExceptionHandler异常协程异常的最后一道拦截&#xff1a;CoroutineExceptionHandlerCoroutineExceptionHandler 为什么只能设置给最外层协程才有效&…...

Android 12.0 debug版本打开OEM解锁开关功能实现

通常为了方便push在debug版本会采用如下命令 adb root adb disable-verity 提示&#xff1a; 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&#xff0c;其id 为2000 2.建立用户组 caiwu&#xff0c;其id 为 2001 3.足建立用户组 jishu&#xff0c;其id 为 2002 4.建立用户lee&#xff0c;指定其主组id为sh…...

[Docker][Docker Container]详细讲解

目录 1.什么是容器&#xff1f;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…...

塑造美好心灵,激发创造活力|第三届瓷艺中华“陶溪川杯”儿童青少年陶瓷作品展开展

第三届瓷艺中华“陶溪川杯”儿童青少年陶瓷作品展 展览现场 由中央美术学院、景德镇陶瓷大学、景德镇陶文旅控股集团共同主办&#xff0c;由中国非物质文化遗产保护协会陶瓷分会、中国文化艺术发展促进会陶瓷专业委员会、中央美术学院陶瓷艺术研究院、中央美术学院少儿美术教…...

鸿蒙开发刷新单个item会闪一下处理

鸿蒙开发刷新单个item会闪一下 首先我用的是懒加载方式,改变某位数据后我调listener.onDataChange(index),发现item的改动是变了,但是item也闪了一下。 先分析为什么item会闪一下 其他是因为item上有图片,加载的网络图。你onDataChange(index)时,它会重新加载这一item,…...

您需要了解的有关 5G 的一切。

转载 https://www.qualcomm.com/5g/what-is-5g 在这里&#xff0c;您可以找到 5G 技术的解释——5G 的工作原理、5G 的重要性以及它如何改变世界连接和沟通的方式。在 Qualcomm&#xff0c;我们发明了使 5G 成为可能的根本性突破。 问&#xff1a;什么是 5G&#xff1f; 答&…...

【redis】初识redis入门,基础部署以及介绍

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…...

数据库基础 -- 数据库约束

数据库基础 – 数据库约束 1.约束 1.1 概念 约束是用于强制数据库中数据 完整性 和 一致性 的规则。它们定义了对表中数据的限制&#xff0c;确保数据的有效性和正确性&#xff0c;实际上就是表中数据的限制条件。 1.2 分类 1.2.1 完整性约束 主键约束(Primary Key Const…...

U盘文件或目录损坏无法读取?专业恢复策略全解析

U盘困境&#xff1a;文件目录的隐形危机 在日常的数字生活中&#xff0c;U盘作为便捷的数据存储与传输工具&#xff0c;扮演着至关重要的角色。然而&#xff0c;当U盘中的文件或目录突然遭遇损坏&#xff0c;导致无法被正常读取时&#xff0c;这无疑给用户带来了极大的困扰。这…...

dpdk实现udp协议栈

使用DPDK实现UDP用户态协议栈&#xff0c;实现流程中包括&#xff1a; 三类线程 1、收发包线程 2、用户态协议栈线程 3、udp服务端线程 两类缓冲区&#xff1a; 1、协议栈收包缓冲区和协议栈发包缓冲区 2、udp收包缓冲区和udp发包缓冲区 协议栈缓冲区中存储的数据是str…...

Shell编程——基础语法(2)和 Shell流程控制

文章目录 基础语法&#xff08;2&#xff09;echo命令read命令printf命令test命令 Shell流程控制if-else语句for 循环while 语句until 循环case ... esac跳出循环 基础语法&#xff08;2&#xff09; echo命令 Shell 的 echo 指令与 PHP 的 echo 指令类似&#xff0c;都是用于…...

Python基础教程(二)字符串和函数

6.字符串 6.1 字符串的表示方式 6.1.1 普通字符串 普通字符串指用单引号()或双引号(”")括起来的字符串。例如:Hello或"Hello" >>> Hello Hello >>> "Hello" Hello >>> s\u0048\u0065\u006c\u006c\u006f >>> …...

智算新风向丨趋动科技获中国信通院泰尔实验室首张智算资源池化能力泰尔测评证书

近日&#xff0c;趋动科技“OrionX AI算力资源池化软件”经中国泰尔实验室依据《FG-Z14-0172-01智算资源池化平台测试方案》评估测试&#xff0c;获得智算资源池化能力泰尔测评证书&#xff0c;成为该领域首个完成此评价的产品。 图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系统在数字化转型中的核心作用与影响

数字化转型是企业利用数字技术改变其业务模式、运营方式、组织结构、产品服务等方面的过程&#xff0c;旨在提高效率、降低成本、增强竞争力并实现可持续发展。数字化转型涉及多个层面&#xff0c;主要包括以下几个方面&#xff1a; 数字化转型转什么 转战略&#xff1a;由构…...

装修施工注意事项

1 地漏保护 咋墙拆改时&#xff0c;一定要用保护盖把所有的地漏下水管道都拧紧 2 卫生间防水做完&#xff0c;必须要先用水泥砂浆做好保护层再贴&#xff0c;不然后续施工&#xff0c;不小心破坏防水层&#xff0c;以后漏水后悔都晚了。 3 入户门口处&#xff0c;一定要用…...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

jmeter聚合报告中参数详解

sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample&#xff08;样本数&#xff09; 表示测试中发送的请求数量&#xff0c;即测试执行了多少次请求。 单位&#xff0c;以个或者次数表示。 示例&#xff1a;…...

Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成

一个面向 Java 开发者的 Sring-Ai 示例工程项目&#xff0c;该项目是一个 Spring AI 快速入门的样例工程项目&#xff0c;旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计&#xff0c;每个模块都专注于特定的功能领域&#xff0c;便于学习和…...