Framer Motion退出动画失效求助:切换视图时元素直接消失
解决Framer Motion退出动画不生效的问题
问题出在哪
- AnimatePresence放错位置:你把AnimatePresence嵌套在HomePage组件内部,切换页面卸载HomePage时,AnimatePresence会跟着被卸载,根本没机会执行exit动画。
- 根动画元素缺少唯一key:AnimatePresence依赖key识别组件的挂载/卸载状态,你HomePage里最外层的motion.div没设置唯一key,它无法判断组件要执行卸载动画。
- 动画属性冲突:比如
comments_container同时应用slideAnimation("down")和fadeAnimation时,后者的exit属性会覆盖前者,导致退出动画不符合预期甚至失效。
修复步骤
1. 迁移AnimatePresence到路由父组件
AnimatePresence需要包裹所有可能切换的页面组件,比如放在路由配置的入口处:
// 路由入口组件示例 import { AnimatePresence } from "framer-motion"; import { Routes, Route, useLocation } from "react-router-dom"; import HomePage from "./HomePage"; import OtherPage from "./OtherPage"; const AppRouter = () => { const location = useLocation(); return ( <AnimatePresence mode="wait"> <Routes location={location} key={location.pathname}> <Route path="/" element={<HomePage />} /> <Route path="/other" element={<OtherPage />} /> </Routes> </AnimatePresence> ); };
加
mode="wait"是为了等待退出动画完成后,再加载新页面的入场动画;给Routes设置key={location.pathname},让AnimatePresence能感知路由切换。
2. 给HomePage根motion元素添加唯一key
删除HomePage内部的AnimatePresence,给最外层motion.div设置唯一标识:
// 修改后的HomePage组件 const HomePage = () => { return ( <motion.div className="card" key="home-page"> {/* 添加唯一key */} <motion.div className="card_section1" {...slideAnimation("left")} key="custom"> <h2 className="title_name">text</h2> <motion.h3 className="subtitle" {...slideAnimation("left")} key="custom2"> {" "} {">"} Front-End Developer </motion.h3> <motion.div className="comments_container" key="custom3" // 手动合并动画属性,避免exit被覆盖 initial={{ ...slideAnimation("down").initial, ...fadeAnimation.initial }} animate={{ ...slideAnimation("down").animate, ...fadeAnimation.animate }} exit={{ ...slideAnimation("down").exit, ...fadeAnimation.exit }} transition={{ ...transition }} > <h6 className="comment">{"//"} explore my projects</h6> <h6 className="comment"> {"//"} you can also see it on my Github page </h6> <h6 className="github"> <span style={{ color: "#4D5BCE" }}>const</span> {" "} <span style={{ color: "#43D9AD" }}>githubLink</span> <span style={{ color: "white" }}> = </span> <a style={{ color: "#E99287" }} href={githubUrl} target="_blank" rel="noreferrer"> text </a> </h6> </motion.div> </motion.div> <motion.div className="card_section2" {...slideAnimation("left")} key="custom4"> <h3>Main Tecnologies</h3> <motion.div className="technologies_image" {...fadeAnimation} key="tech-images"> {Images.map((image, i) => { return <img key={i} src={image} alt={image} />; })} </motion.div> </motion.div> </motion.div> ); };
3. 修复动画属性冲突
同时应用多个动画对象时,直接展开会覆盖同名属性,需要手动合并initial、animate、exit状态,确保所有动画效果都能生效(如上面的comments_container组件)。
额外提醒
- AnimatePresence必须在要卸载的组件外层,不能和组件同时被卸载。
- 每个motion元素的key要唯一,避免用随机值或列表索引作为关键元素的key。
- 使用React Router v6时,必须给
Routes传递location和key属性,否则AnimatePresence无法检测路由变化。
内容的提问来源于stack exchange,提问作者Bigbool98
相关产品推荐
相关产品推荐

