You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.02 04:13:13