如何通过Framer Motion触发AnimatePresence退出动画并实现文本轮播?
解决Framer-Motion文本轮播的退出动画与循环切换问题
你的核心问题在于**repeat: Infinity只会重复initial到animate的过渡,不会触发exit动画**——因为exit需要组件从DOM中卸载才会执行,而重复动画只是在同一个组件上反复执行样式变化。要实现完整的轮播流程,需要通过状态控制组件的挂载/卸载,配合AnimatePresence来触发完整的进入→停留→退出→切换文本的循环。
实现方案
- 用状态管理当前显示的文本索引
- 借助定时器,在文本停留指定时间后,触发退出动画并切换到下一段文本
- 利用
AnimatePresence的mode="wait"确保前一个文本完全退出后,再加载下一个文本 - 通过修改组件的
key值,让AnimatePresence识别组件变化,触发卸载/挂载动画
完整代码示例
import { useState, useEffect } from "react"; import { motion, AnimatePresence } from "framer-motion"; const TextCarousel = () => { // 轮播文本列表 const texts = ["文本1", "文本2", "文本3"]; // 当前显示的文本索引 const [currentIndex, setCurrentIndex] = useState(0); // 动画时间配置:进入/退出动画时长、停留时长 const animationConfig = { enterDuration: 0.5, exitDuration: 0.5, stayDuration: 2 }; useEffect(() => { // 定时器:停留指定时间后,切换到下一个文本 const timer = setTimeout(() => { setCurrentIndex((prev) => (prev + 1) % texts.length); }, (animationConfig.enterDuration + animationConfig.stayDuration) * 1000); return () => clearTimeout(timer); }, [currentIndex, animationConfig]); return ( <AnimatePresence mode="wait"> <motion.span key={currentIndex} initial={{ x: 200, opacity: 0 }} animate={{ x: 0, opacity: 1 }} exit={{ x: -200, opacity: 0 }} transition={{ duration: animationConfig.enterDuration, exit: { duration: animationConfig.exitDuration } }} style={{ display: "inline-block" }} > {texts[currentIndex]} </motion.span> </AnimatePresence> ); }; export default TextCarousel;
关键细节说明
- 触发exit动画:当
currentIndex变化时,motion.span的key值改变,AnimatePresence会将旧组件卸载,此时自动执行exit配置的动画。 - 文本切换与循环:通过
(prev + 1) % texts.length实现索引的循环递增,到达最后一个文本后回到第一个。 - 动画时序控制:定时器的延迟时间为「进入动画时长 + 停留时长」,确保文本完全进入并停留足够时间后再开始退出。
mode="wait":保证前一个文本的exit动画完全结束后,再渲染下一个文本的initial动画,避免重叠。
内容的提问来源于stack exchange,提问作者Horkos
相关产品推荐
相关产品推荐

