Next.js 16.2.6搭配Framer Motion 12.4.0退出动画失效求助
Framer Motion v12.4.0 页面切换退出动画不生效解决方案
核心问题分析
退出动画不生效的核心原因通常是:AnimatePresence 未正确监听页面组件的卸载/重新挂载、缺少唯一标识页面的 key 属性,或未配置 wait 模式确保退出动画完成后再执行进入动画。
分步解决方案
1. 配置全局页面过渡容器(客户端组件)
创建一个专门的过渡包裹组件,使用 AnimatePresence 并传入当前路由路径作为唯一 key,同时开启 mode="wait" 保证动画顺序:
// app/components/PageTransitionWrapper.tsx 'use client'; import { AnimatePresence } from 'framer-motion'; import { usePathname } from 'next/navigation'; export default function PageTransitionWrapper({ children }: { children: React.ReactNode }) { const pathname = usePathname(); // 获取当前路由路径作为唯一key return ( <AnimatePresence mode="wait"> <div key={pathname}>{children}</div> </AnimatePresence> ); }
2. 在根布局中引入过渡容器
将过渡容器嵌入根布局,导航栏放在容器外避免参与页面过渡:
// app/layout.tsx import Navbar from './components/Navbar'; import PageTransitionWrapper from './components/PageTransitionWrapper'; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="zh-CN"> <body> <Navbar /> <PageTransitionWrapper>{children}</PageTransitionWrapper> </body> </html> ); }
3. 编写页面动画包裹组件
为每个页面配置包含 exit 属性的 motion.div,确保退出动画被正确定义:
// app/components/PageAnimation.tsx 'use client'; import { motion } from 'framer-motion'; export default function PageAnimation({ children }: { children: React.ReactNode }) { return ( <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -20 }} // 必须明确配置退出动画 transition={{ duration: 0.5 }} style={{ width: '100%', minHeight: 'calc(100vh - 60px)' }} // 根据导航栏高度调整 > {children} </motion.div> ); }
4. 为每个页面应用动画组件
所有页面都需要用上述动画组件包裹:
// app/page.tsx(首页示例) import PageAnimation from './components/PageAnimation'; export default function Home() { return ( <PageAnimation> <h1>首页</h1> {/* 其他首页内容 */} </PageAnimation> ); }
5. 确保使用客户端路由导航
导航栏必须使用 Next.js 的 Link 组件,而非原生 <a> 标签,保证客户端路由触发组件卸载/挂载:
// app/components/Navbar.tsx import Link from 'next/link'; export default function Navbar() { return ( <nav style={{ padding: '1rem', background: '#f5f5f5' }}> <Link href="/" style={{ marginRight: '1rem' }}>首页</Link> <Link href="/about" style={{ marginRight: '1rem' }}>关于页</Link> <Link href="/contact">联系页</Link> </nav> ); }
常见错误排查
- 不要在
AnimatePresence和页面元素之间添加无key的层级组件,否则会中断动画监听。 - 检查
exit属性拼写是否正确(避免写成exits),动画参数是否合理。 - 确保页面元素未被 CSS 的
display: none或visibility: hidden提前隐藏,Framer Motion 需要元素留在 DOM 中直到动画完成。
内容的提问来源于stack exchange,提问作者user32755166
相关产品推荐
相关产品推荐

