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

Next.js 13.4.19中Framer Motion动画无法正常工作的问题

解决Next.js 13.4.19中Framer Motion动画不生效的问题

你的动画未生效主要有两个核心原因:Framer Motion的exit动画必须依赖AnimatePresence组件触发,以及Next.js App Router的服务器渲染特性可能影响初始动画的执行。以下是具体解决方案:

1. 用AnimatePresence包裹组件以启用exit动画

exit属性只有在组件被AnimatePresence直接包裹,且组件拥有唯一key时才会触发。你当前的代码缺少这一层包裹,所以退出动画完全不会运行。

方案1:将page.js转为客户端组件

直接修改page.js,添加"use client"指令并引入AnimatePresence:

"use client";
import { AnimatePresence } from "framer-motion";
import Navbar from "@/components/Navbar";

export default function Home() {
  return (
    <AnimatePresence mode="wait">
      <Navbar key="navbar" />
    </AnimatePresence>
  );
}
  • mode="wait":确保退出动画执行完成后再移除组件
  • key="navbar":让AnimatePresence识别组件的挂载/卸载状态

方案2:创建客户端包裹组件(不修改page.js)

如果不想把page.js转为客户端组件,可新建NavbarWrapper.js:

"use client";
import { AnimatePresence } from "framer-motion";
import Navbar from "./Navbar";

export default function NavbarWrapper() {
  return (
    <AnimatePresence mode="wait">
      <Navbar key="navbar" />
    </AnimatePresence>
  );
}

然后在page.js中引入这个包裹组件:

import NavbarWrapper from "@/components/NavbarWrapper";

export default function Home() {
  return (
    <>
      <NavbarWrapper />
    </>
  );
}

2. 确保初始动画在客户端正常执行

如果初始动画仍不生效,可能是服务器渲染的内容与客户端 hydration 存在差异,可通过useAnimation和useEffect手动触发动画:
修改Navbar组件:

"use client";
import { motion, useAnimation } from "framer-motion";
import { useEffect } from "react";

export default function Navbar() {
  const controls = useAnimation();

  useEffect(() => {
    // 在客户端 hydration 完成后触发动画
    controls.start({ opacity: 1, y: 0 });
  }, [controls]);

  return (
    <motion.div
        initial={{ opacity: 0, y: 15 }}
        animate={controls}
        exit={{ opacity: 0, y: 15 }}
        transition={{ delay: 0.25 }}
    >
      <div className="w-full h-[112px] bg-primary"></div>
    </motion.div>
  );
}

3. 页面切换时的exit动画适配

如果需要在路由切换时触发Navbar的exit动画,需在根布局layout.js中用AnimatePresence包裹页面内容,并监听路由路径作为key:

"use client";
import { AnimatePresence } from "framer-motion";
import { usePathname } from "next/navigation";

export default function RootLayout({ children }) {
  const pathname = usePathname();

  return (
    <html lang="en">
      <body>
        <AnimatePresence mode="wait">
          {/* 将Navbar放在布局中,用路由路径作为key */}
          <Navbar key={pathname} />
          {children}
        </AnimatePresence>
      </body>
    </html>
  );
}

内容的提问来源于stack exchange,提问作者kartik kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 07:35:37