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
相关产品推荐
相关产品推荐

