React中实现文本切换时重复触发打字机动画的方法
解决React文本切换时重复触发打字机动画的问题
问题背景
我在React组件中实现了每4秒随机切换文本的功能,但当前的打字机动画仅在组件初始加载时触发,无法在每次文本切换时重复执行。相关代码如下:
JSX结构
<div className="fullscreen-text"> <p>{loadingPhrases[phraseIndex]}</p> </div>
文本切换逻辑
useEffect(() => { const interval = setInterval(() => { setPhraseIndex(Math.floor(Math.random() * 9)); }, 4000); return () => clearInterval(interval); }, []);
当前CSS样式
.fullscreen-text { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: #fff; font-size: 36px; font-family: 'Open Sans', sans-serif; display: inline-block; overflow: hidden; white-space: nowrap; animation: typewriter 5s steps(60) forwards; } @keyframes typewriter { from { width: 0; } to { width: 100%; } }
解决方案
下面提供三种可行的实现方式,按需选择:
方法1:利用React的key属性强制重渲染
React会根据元素的key值判断是否需要重新创建组件。当phraseIndex变化时,更新key值即可让组件重新挂载,从而触发CSS动画:
<div className="fullscreen-text" key={phraseIndex}> <p>{loadingPhrases[phraseIndex]}</p> </div>
这种方式最简单,无需修改CSS或额外逻辑,适合快速解决问题。
方法2:手动控制动画类的添加与移除
将动画定义在单独的CSS类中,通过状态控制类的添加/移除,每次文本切换时重置动画:
- 修改CSS,拆分基础样式与动画类:
.fullscreen-text { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: #fff; font-size: 36px; font-family: 'Open Sans', sans-serif; display: inline-block; overflow: hidden; white-space: nowrap; } .typewriter-animate { animation: typewriter 5s steps(60) forwards; } @keyframes typewriter { from { width: 0; } to { width: 100%; } }
- 在组件中添加状态控制动画:
import { useState, useEffect } from 'react'; // 组件内部状态 const [isAnimating, setIsAnimating] = useState(true); // 当phraseIndex变化时重置动画 useEffect(() => { // 先移除动画类 setIsAnimating(false); // 延迟10ms让浏览器识别样式变化,再重新添加动画类 const timer = setTimeout(() => setIsAnimating(true), 10); return () => clearTimeout(timer); }, [phraseIndex]); // JSX部分 <div className={`fullscreen-text ${isAnimating ? 'typewriter-animate' : ''}`}> <p>{loadingPhrases[phraseIndex]}</p> </div>
方法3:使用Web Animations API手动触发
通过原生JS的Web Animations API直接控制动画,灵活性更强,无需依赖CSS类的切换:
import { useState, useEffect, useRef } from 'react'; // 组件内部 const textContainerRef = useRef(null); // 每次phraseIndex变化时触发动画 useEffect(() => { const container = textContainerRef.current; if (!container) return; // 重置宽度为0 container.style.width = '0'; // 执行打字机动画 container.animate( [{ width: '0' }, { width: '100%' }], { duration: 5000, steps: 60, fill: 'forwards' } ); }, [phraseIndex]); // JSX部分 <div className="fullscreen-text" ref={textContainerRef}> <p>{loadingPhrases[phraseIndex]}</p> </div>
此时可以移除原CSS中的animation属性,保留基础布局样式即可。
内容的提问来源于stack exchange,提问作者kirvel
相关产品推荐
相关产品推荐

