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

如何在React中动态修改已有元素的className

记忆游戏答题正误反馈:动态修改元素类名实现闪色效果

问题描述

我正在开发一款简易记忆游戏,希望通过修改已有元素的className,使其在玩家猜对答案时闪绿色、猜错时闪红色,目前仅能在控制台打印'CORRECT'和'WRONG'。

现有代码

渲染需变色元素的函数

const renderMajorSegment = (musicKey, index) => {
  let arc = calculateArc(outerRadius, innerRadius, musicKey.segmentMetadata.startAngle, musicKey.segmentMetadata.endAngle);
  let [arcCenterX, arcCenterY] = arc.centroid();

  return <g className={`circle-segment ${musicKey.segmentMetadata.majorCircle.isVisible ? 'isVisible': ''}`} 
            key={index}>
          <path 
            d={arc.apply()} // apply() is needed to generate the string that goes into the 'd' attribute
          />
          <text x={arcCenterX} y={arcCenterY} transform={`rotate(15, ${arcCenterX}, ${arcCenterY})`}>
            {abbreviateKeyFromChord(musicKey.chords[0])}
          </text>
        </g>
}

函数组件核心部分

return (
  <div className='circle-of-fifths-container'>
    <svg
      height={diameter*1.1}
      width={diameter*1.1}>
      <g className='circle-container' transform={`translate(${diameter/2 + 25},${diameter/2 + 25}) rotate(-15)`}>
        <circle r={outerRadius} className='base-circle'/>
        <g className='outer-circle-segments-container'>
          {musicKeysObject.map((musicKey, index) => renderMajorSegment(musicKey, index))}
        </g>
        <g className='inner-circle-segments-container'>
          {musicKeysObject.map((musicKey, index) => renderMinorSegment(musicKey, index))}
        </g>
        {mode === READY && 
          <g id='play-button-container' onMouseUp={startRound}>
            <circle r={innerRadius2} id='play-button'/>
            <text id='play-button-text' transform='rotate(15)'>PLAY GAME</text>
          </g>}
      </g>
    </svg>
    {mode === PLAYING &&
      <input placeholder='Your answer' onKeyDown={handleUserInput}></input>
    }
  </div>
)

处理用户输入的逻辑函数

const handleUserInput = (event) => {
  var index;
  if (hiddenSegment.major) {
    index = 0;
  } else {
    index = 5;
  }

  if (event.key === 'Enter') {
    if (event.target.value === abbreviateKeyFromChord(hiddenSegment.chords[index])) {
      console.log('CORRECT');
      // Set both major and minor circles to true
      // 1 will already be true so it makes no difference, sets the non-visible one to true
      hiddenSegment.segmentMetadata.majorCircle.isVisible = true;
      hiddenSegment.segmentMetadata.minorCircle.isVisible = true;

      // Modify the css classes to make the segments go green

      startRound();
    } else {
      // Modify the css classes to make the segments go red
      console.log('WRONG');
    }
  }
};

我的思路

我梳理了两种可能的实现方向:

  • 给renderMajorSegment()添加参数,根据正误状态字符串修改className;
  • 通过React状态存储正误标识,参考现有isVisible的用法动态修改类名。

解决方案

推荐使用React状态管理的方案,更符合React数据流模式,避免直接修改数据对象的不可控问题。具体步骤如下:

1. 添加状态存储答题反馈

在组件中新增状态,记录当前答题的正误状态和对应的目标片段索引:

const [feedback, setFeedback] = useState({
  segmentIndex: null,
  isCorrect: null
});

2. 修改渲染函数,动态添加反馈类名

更新renderMajorSegment,根据状态判断是否添加闪色类名(renderMinorSegment做相同修改即可):

const renderMajorSegment = (musicKey, index) => {
  let arc = calculateArc(outerRadius, innerRadius, musicKey.segmentMetadata.startAngle, musicKey.segmentMetadata.endAngle);
  let [arcCenterX, arcCenterY] = arc.centroid();
  
  // 根据当前反馈状态判断是否添加闪色类
  const feedbackClass = feedback.segmentIndex === index 
    ? feedback.isCorrect ? 'flash-green' : 'flash-red' 
    : '';

  return <g className={`circle-segment ${musicKey.segmentMetadata.majorCircle.isVisible ? 'isVisible': ''} ${feedbackClass}`} 
            key={index}>
          <path d={arc.apply()} />
          <text x={arcCenterX} y={arcCenterY} transform={`rotate(15, ${arcCenterX}, ${arcCenterY})`}>
            {abbreviateKeyFromChord(musicKey.chords[0])}
          </text>
        </g>
}

3. 更新输入处理函数,设置并自动清除反馈状态

修改handleUserInput,设置反馈状态后自动清除,实现闪烁效果:

const handleUserInput = (event) => {
  var index;
  if (hiddenSegment.major) {
    index = 0;
  } else {
    index = 5;
  }

  // 找到当前hiddenSegment在musicKeysObject中的索引
  const segmentIndex = musicKeysObject.findIndex(key => key === hiddenSegment);

  if (event.key === 'Enter') {
    const isCorrect = event.target.value === abbreviateKeyFromChord(hiddenSegment.chords[index]);
    
    if (isCorrect) {
      console.log('CORRECT');
      hiddenSegment.segmentMetadata.majorCircle.isVisible = true;
      hiddenSegment.segmentMetadata.minorCircle.isVisible = true;
    } else {
      console.log('WRONG');
    }

    // 设置反馈状态,触发视图更新
    setFeedback({ segmentIndex, isCorrect });
    
    // 1秒后清除反馈,结束闪烁;答对则进入下一轮
    setTimeout(() => {
      setFeedback({ segmentIndex: null, isCorrect: null });
      if (isCorrect) startRound();
    }, 1000);
    
    // 清空输入框
    event.target.value = '';
  }
};

4. 添加CSS闪烁动画

在样式文件中定义闪色动画:

@keyframes flash-green {
  0% { fill: #2ecc71; }
  50% { fill: initial; }
  100% { fill: #2ecc71; }
}

@keyframes flash-red {
  0% { fill: #e74c3c; }
  50% { fill: initial; }
  100% { fill: #e74c3c; }
}

.flash-green path {
  animation: flash-green 1s ease-in-out;
}

.flash-red path {
  animation: flash-red 1s ease-in-out;
}

方案说明

  • 采用React状态管理反馈信息,符合单向数据流原则,避免直接修改数据导致的视图不更新问题;
  • 通过setTimeout自动清除状态,实现自动结束闪烁的效果;
  • CSS动画实现闪烁,性能优于JavaScript操作样式;
  • 同时支持major和minor片段的反馈,只需同步修改renderMinorSegment即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 01:40:09