Framer Motion中Animate Presence exit属性对数组元素失效问题
解决Framer Motion逐个淡入淡出标题的问题
你的代码有两个核心问题导致效果不符合预期:
- 直接在
map回调里调用updateList会触发无限重渲染,而且逻辑错误——初始渲染时就把所有元素从列表里过滤掉了,根本没法实现逐个切换的逻辑 - 一次性渲染所有
<motion.span>元素,AnimatePresence无法检测到单个元素的卸载动作,自然不会触发淡出动画,所有元素会同时执行淡入
修正方案
要实现逐个淡入再淡出的轮播效果,正确的思路是一次只渲染当前要显示的标题,通过切换状态让旧标题卸载(触发淡出)、新标题挂载(触发淡入),具体代码如下:
import { useState, useEffect } from 'react'; import { AnimatePresence, motion } from 'framer-motion'; export default function Title() { const texts = [ {text: "UNLEASH YOUR POWER", id: 1}, {text: "SURRENDER TO YOUR FEELINGS", id: 2}, {text: "RELEASE INNER BEAST", id: 3}, {text: "EXPLORE PREDATOR SENSE", id: 4} ]; // 跟踪当前显示的文本索引 const [currentIndex, setCurrentIndex] = useState(0); useEffect(() => { // 设置定时器,每隔2秒切换一次标题(可根据需求调整时长) const interval = setInterval(() => { setCurrentIndex(prev => (prev + 1) % texts.length); }, 2000); // 清理定时器 return () => clearInterval(interval); }, [texts.length]); return ( <div className='title'> {/* mode="wait" 确保前一个元素的淡出动画完成后,再执行下一个的淡入 */} <AnimatePresence mode="wait"> {/* 每次只渲染当前索引对应的标题 */} <motion.span key={texts[currentIndex].id} initial={{ opacity: 0, scale: 0.5 }} animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.5 }} transition={{ duration: 0.8, ease: [0, 0.71, 0.2, 1.01] }} > {texts[currentIndex].text} </motion.span> </AnimatePresence> </div> ); }
关键说明
- 状态管理:用
currentIndex替代原来的list状态,只跟踪当前显示的标题位置,避免不必要的数组操作 - 定时器切换:通过
useEffect设置定时任务,循环切换索引,实现自动轮播 - AnimatePresence配置:
mode="wait"参数保证动画顺序,防止新旧标题动画重叠 - 动画逻辑:每个标题挂载时执行淡入放大,卸载时执行淡出缩小,完全符合你要的逐个切换效果
内容的提问来源于stack exchange,提问作者83hru2
相关产品推荐
相关产品推荐

