You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React中动态修改组件样式,实现类似monkeytype的打字效果

解决方案

React属于声明式UI框架,不需要保存组件实例、手动调用组件方法来更新样式,所有UI变化都可以通过状态驱动实现,具体实现逻辑如下:


核心思路

在父组件TypeTest中维护3个核心状态,通过状态判断当前输入的单词位置,将状态通过props传递给Word组件,由Word组件根据props自主计算要渲染的样式即可:

  1. 当前输入的单词索引:用来定位「当前」正在输入的单词
  2. 当前单词的用户输入内容:用来做字符级别的正误判断
  3. 已完成单词的正误状态:用来给已输入完成的单词添加对应样式

代码实现

父组件TypeTest代码

import { useState, useEffect, useCallback } from 'react';
import Word from './word'; 
import './typeTest.css'

export default function TypeTest() {
    const test1 = "the quick brown fox jumped over a tree and tripped over that tree the quick brown fox jumped over a tree and tripped over that tree the quick brown fox jumped over a tree and tripped over that tree the quick brown fox jumped over a tree and tripped over that tree"; 
    const test1Arr = test1.split(' '); 
    // 核心状态定义
    const [currentWordIdx, setCurrentWordIdx] = useState(0); // 当前输入的单词索引
    const [currentInput, setCurrentInput] = useState(''); // 当前单词的用户输入内容
    const [completedWords, setCompletedWords] = useState([]); // 已完成单词的正误状态

    // 键盘输入监听逻辑
    const handleKeyDown = useCallback((e) => {
        // 按空格完成当前单词输入
        if (e.key === ' ') {
            e.preventDefault();
            const isCorrect = currentInput === test1Arr[currentWordIdx];
            setCompletedWords(prev => [...prev, {isCorrect}]);
            setCurrentWordIdx(prev => prev + 1);
            setCurrentInput('');
            return;
        }
        // 按退格且当前单词输入为空时,回到上一个单词修改
        if (e.key === 'Backspace' && currentInput.length === 0 && currentWordIdx > 0) {
            setCurrentWordIdx(prev => prev - 1);
            setCompletedWords(prev => prev.slice(0, -1));
            setCurrentInput(test1Arr[currentWordIdx - 1]);
            return;
        }
        // 普通字符输入逻辑,过滤功能键
        if (e.key.length === 1 && !e.ctrlKey && !e.metaKey) {
            setCurrentInput(prev => prev + e.key);
        }
    }, [currentInput, currentWordIdx, test1Arr]);

    // 绑定/解绑全局键盘监听
    useEffect(() => {
        window.addEventListener('keydown', handleKeyDown);
        return () => window.removeEventListener('keydown', handleKeyDown);
    }, [handleKeyDown]);

    return (
        <div className='outer-word-container'>
            <div className="word-container" tabIndex={0}>
                {test1Arr.map((monoWord, index) => (
                    <Word 
                        key={index}
                        inputWord={monoWord}
                        isActive={index === currentWordIdx} // 标记是否是当前输入的单词
                        isCompleted={index < currentWordIdx} // 标记是否是已完成的单词
                        isCorrect={completedWords[index]?.isCorrect} // 已完成单词的正误标记
                        userInput={index === currentWordIdx ? currentInput : ''} // 当前单词的用户输入内容
                    />
                ))}
                <Word inputWord="Scroll"/>
            </div>
        </div>
    )
}

Word组件示例代码

// Word.jsx
export default function Word({inputWord, isActive, isCompleted, isCorrect, userInput}) {
    // 字符级别的样式渲染
    const renderChars = () => {
        return inputWord.split('').map((char, idx) => {
            let className = 'char';
            // 已输入字符判断正误
            if (idx < userInput.length) {
                className += userInput[idx] === char ? ' correct' : ' wrong';
            }
            // 当前待输入字符加光标高亮
            if (idx === userInput.length && isActive) {
                className += ' current-cursor';
            }
            return <span key={idx} className={className}>{char}</span>
        })
    }

    // 单词级别的样式渲染
    let wordClass = 'word';
    if (isActive) wordClass += ' active-word';
    if (isCompleted) wordClass += isCorrect ? ' correct-word' : ' wrong-word';

    return <span className={wordClass}>{renderChars()}</span>
}

补充说明

你可以根据需求自行调整CSS规则,比如给正确单词设置绿色、错误单词设置红色、当前输入单词加下划线高亮、待输入字符加闪烁光标效果等,所有样式变化都通过状态驱动,完全不需要手动操作组件实例或者调用组件方法,符合React的开发规范,也更容易维护。

内容的提问来源于stack exchange,提问作者sharkeater123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 05:54:03