Framer Motion中如何在组件已渲染时动态修改exit动画参数值
Framer Motion中如何在组件已渲染时动态修改exit动画参数值
嘿,我完全懂你碰到的这个麻烦——当你跨标签页跳转(比如从第2页直接跳到第3页)时,退出的页面动画方向完全不对,因为当前的exit参数是组件渲染时就固定死的,没法跟着新的跳转方向动态更新对吧?我来给你几个实用的解决方案,帮你搞定这个问题:
方案一:拆分「进入方向」和「退出方向」,用AnimatePresence控制时序
你的核心问题在于,现在全局的direction状态既管进入动画又管退出动画,但这两个方向其实是相反的(比如从页1到页2,页1退出方向是-100%,页2进入方向是100%)。我们可以把这两个状态分开:
修改导航组件的handleChange逻辑:
const handleChange = (event, newValue) => { const oldValue = value; // 计算「旧页面的退出方向」:新页面索引更大,旧页面向左退;反之向右退 const exitDirection = newValue > oldValue ? "-100%" : "100%"; // 计算「新页面的进入方向」:和退出方向正好相反 const enterDirection = newValue > oldValue ? "100%" : "-100%"; // 先更新退出方向,让即将卸载的页面拿到正确的exit参数 setExitDirection(exitDirection); // 再更新进入方向,给新页面用 setDirection(enterDirection); // 别忘了存到localStorage localStorage.setItem("bottomNavSelectedValue", newValue.toString()); // 最后切换页面值 setValue(newValue); };用AnimatePresence包裹页面,开启wait模式:
一定要用AnimatePresence才能让exit动画生效,而且mode="wait"会等旧页面退出动画完成后再加载新页面,避免动画重叠:import { AnimatePresence, motion } from "framer-motion"; // 页面容器组件 const PageContainer = ({ value, direction, exitDirection }) => { return ( <AnimatePresence mode="wait"> {value === 0 && ( <motion.div className="body" initial={{ x: direction }} animate={{ x: 0 }} exit={{ x: exitDirection }} transition={{ duration: 0.2 }} > {/* 页1内容 */} </motion.div> )} {value === 1 && ( <motion.div className="body" initial={{ x: direction }} animate={{ x: 0 }} exit={{ x: exitDirection }} transition={{ duration: 0.2 }} > {/* 页2内容 */} </motion.div> )} {/* 其他页面同理 */} </AnimatePresence> ); };
方案二:让每个页面自己计算退出方向(更灵活)
如果不想维护全局的退出方向状态,也可以让每个页面组件根据自身索引和当前选中的索引,自己算出该用什么退出方向:
import { motion, AnimatePresence } from "framer-motion"; import { useEffect, useRef, useState } from "react"; const PageComponent = ({ index, currentIndex }) => { const [exitX, setExitX] = useState(0); // 用ref保存上一次的选中索引,用来判断当前页面是否要退出 const prevCurrentIndexRef = useRef(currentIndex); useEffect(() => { // 当选中索引变化,且之前选中的是当前页面时,计算退出方向 if (prevCurrentIndexRef.current === index) { setExitX(currentIndex > index ? "-100%" : "100%"); } // 更新ref的值 prevCurrentIndexRef.current = currentIndex; }, [currentIndex, index]); // 计算进入方向 const enterDirection = currentIndex > index ? "-100%" : "100%"; return ( <motion.div className="body" initial={{ x: enterDirection }} animate={{ x: 0 }} exit={{ x: exitX }} transition={{ duration: 0.2 }} > {/* 页面内容 */} </motion.div> ); }; // 页面容器调用示例 const PageContainer = ({ currentIndex }) => { return ( <AnimatePresence mode="wait"> <PageComponent index={0} currentIndex={currentIndex} /> <PageComponent index={1} currentIndex={currentIndex} /> <PageComponent index={2} currentIndex={currentIndex} /> </AnimatePresence> ); };
这种方式不需要全局维护方向状态,每个页面自己处理动画逻辑,跨标签跳转时也能精准计算退出方向。
关键注意点
- 必须用
AnimatePresence包裹动态切换的组件,否则Framer Motion的exit动画不会触发; mode="wait"是核心,它能确保旧页面完全退出后再加载新页面,避免动画混乱;- 不要把进入方向和退出方向混为一谈,两者在跨页跳转时是相反的,必须分开处理。
备注:内容来源于stack exchange,提问作者stevenyoussef
相关产品推荐
相关产品推荐

