在本文中,我们将一起创建一个打字速度测试器。这个应用会为用户提供一段随机的段落,用户需要在一分钟的固定时间限制内,尽可能快速且准确地输入这些内容。此外,我们的应用还会实时显示剩余时间,统计错误次数,计算每分钟字数(WPM)和每分钟字符数(CPM),并动态更新这些数据。用户可以通过点击重置按钮来重新开始游戏,并尝试一段新的段落。这个应用是使用 JSX 实现的,并采用了简洁的用户界面设计。
最终输出预览:
!Screenshot-2023-09-22-154403使用React构建的打字速度测试器预览图
前提条件和技术:
实现思路:
利用 ReactJS 的函数式组件和状态管理,我们将创建一个基于 Web 的交互式打字速度测试器。它能提供随机段落的实时打字挑战。用户可以通过按下键盘上的按键来输入段落中的字符。我们的应用会跟踪剩余时间,计算 WPM 和 CPM,同时统计错误数并向用户动态展示。这个应用旨在提供一种引人入胜的打字体验,鼓励用户在时间限制内提高打字速度和准确率。
创建应用的步骤:
第1步: 使用以下命令设置 React 项目
npm create vite@latest typing-speed-tester --template react
第2步: 导航到项目文件夹
cd typing-speed-tester
第3步: 安装依赖项
npm install
第4步: 创建一个名为 “components” 的文件夹,并在其中添加三个新文件:INLINECODE65c3dcda、INLINECODEe0652a1c 和 TypingArea.js。
项目结构:
!Screenshot-2023-09-20-141351项目结构
package.json 中的更新后的依赖项将如下所示:
{
"name": "typing-speed-tester",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"vite": "^4.0.0",
"web-vitals": "^2.1.4"
},
"devDependencies": {
"@vitejs/plugin-react": "^2.0.0"
}
}
示例: 在相应的文件中编写以下代码
- App.js: 此文件用于导入 SpeedTypingGame 组件并将其导出。
- SpeedTypingGame.js: 管理游戏的状态和逻辑,包括段落生成和用户输入处理。
- TypingArea.js: 渲染打字区域和统计数据,跟踪时间、错误,并提供重置按钮。
- SpeedTypingGame.css: 此文件包含 SpeedTypingGame 元素的设计样式。
CSS
“
/ SpeedTypingGame.css /
body{
padding: 0;
margin: 0;
box-sizing: border-box;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: ‘Noto Sans Mono‘, monospace;
background-color: #e7e9e9;
}
.container {
max-width: 650px;
margin: 5px;
width: calc(100% – 10px);
padding: 30px;
border-radius: 10px;
box-sizing: border-box;
border: 1px solid #ced4da;
background: #fff;
box-shadow: 0 0 6px rgba(0,0,0,0.25);
}
input.input-field{
opacity: 0;
z-index: -999;
position: absolute;
}
#paragraph{
word-break: break-all;
text-align: left;
}
.section{
border: 1px solid #ced4da;
border-radius: 5px;
padding: 20px;
padding-top: 0;
}
.section1{
border-bottom: 1px solid #ced4da;
}
span{
font-size: 20px;
user-select: none;
cursor: tex;
}
span.wrong{
color: darkred;
background-color: pink;
}
span.correct{
color: #0e630e;
background: #e7fbd3;
}
span.active{
border-bottom: 3px solid #0a6bf9;
}
.section2{
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 5px;
}
.section2 ul{
padding-inline-start: 0px;
display: flex;
justify-content: space-between;
align-items: center;
margin: 0px;
width: calc(100% – 120px);
}
.section2 ul li{
list-style-type: none;
margin: 0 10px;
}
.section2 ul li p{
margin: 5px;
font-size: 12px;
}
.section2 ul li span{
font-size: 18px;
}
button.btn {
padding: 10px 20px;
outline: none;
border: 1px solid #ced4da;
margin: 5px;
border-radius: 4px;
cursor: pointer;
background: #1d9bf0;
color: #fff;
font-size: 16px;
transition: all 0.5s;
}
button.btn:hover{
background-color: #1879ba;
}
@media screen and (max-width : 550px){
.section2{
flex-direction: column;
}
.section2 ul{
width: 100%;
justify-content: space-between;
}
button.btn{
width: 100%;
margin-top: