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

React技术问题:如何仅在首次渲染时应用CSS打字机效果?

解决React组件重渲染时打字机动画重复触发的问题

你的问题核心在于CSS动画默认会在元素每次被添加到DOM时触发,若组件重渲染时DOM元素被重新挂载(如key变化)或类名重复设置,都会导致动画重新执行。以下是两种可靠的解决方案,确保动画仅在首次渲染时生效:

方案一:通过控制类名触发动画

利用useRef标记动画是否已执行,仅在组件首次挂载时添加动画类:

import React, { useEffect, useRef, useState } from 'react';
import './Typewriter.css';

export function Blah() {
  // 标记动画是否已执行过
  const hasAnimated = useRef(false);
  const [showAnimation, setShowAnimation] = useState(false);

  useEffect(() => {
    if (!hasAnimated.current) {
      hasAnimated.current = true;
      // 首次挂载时启用动画类
      setShowAnimation(true);
    }
  }, []); // 空依赖确保仅在组件首次挂载时执行

  return (
    <div className={showAnimation ? 'typewriter' : ''}>
      My typewriter text here
    </div>
  );
}

你的原有CSS无需修改,动画只会在类名首次添加时触发,后续重渲染时showAnimation保持为true,类名不会重复切换,动画也就不会重新执行。

方案二:结合DOM属性与CSS选择器控制动画

通过给DOM元素添加标记属性,让CSS仅在首次渲染时执行动画:

组件代码

import React, { useEffect, useRef } from 'react';
import './Typewriter.css';

export function Blah() {
  const typewriterRef = useRef(null);

  useEffect(() => {
    const element = typewriterRef.current;
    if (element && !element.dataset.animated) {
      // 动画执行完成后标记为已动画
      const handleAnimationEnd = () => {
        element.dataset.animated = 'true';
        element.removeEventListener('animationend', handleAnimationEnd);
      };
      element.addEventListener('animationend', handleAnimationEnd);
    }
  }, []);

  return (
    <div ref={typewriterRef} className="typewriter">
      My typewriter text here
    </div>
  );
}

修改后的CSS

/* 仅在未标记已动画时执行打字机效果 */
.typewriter:not([data-animated="true"]) {
    font-family: monospace;
    color:#0000;
    background:
            linear-gradient(-90deg, #39ff14 5px,#0000 0) 10px 0,
            linear-gradient(#39ff14 0 0) 0 0;
    background-size:calc(100*1ch) 200%;
    -webkit-background-clip:padding-box,text;
    background-clip:padding-box,text;
    background-repeat:no-repeat;
    animation:
            b .7s infinite steps(1),
            t calc(100*.01s) steps(100) forwards;
}

/* 已完成动画的静态样式 */
.typewriter[data-animated="true"] {
    font-family: monospace;
    color: #39ff14;
    background: none;
}

@keyframes t{
    from {background-size:0 200%}
}
@keyframes b{
    50% {background-position:0 -100%,0 0}
}

这个方案通过监听animationend事件,在打字机动画完成后给元素添加data-animated属性,后续重渲染时CSS会匹配静态样式,不再触发动画。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 21:50:52