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

使用Framer Motion的AnimatePresence实现侧边菜单退出动画失效问题

问题分析与解决方案

你的侧边菜单退出动画不生效的核心原因是 AnimatePresence 的位置错误,以及几处小的代码问题:

  1. AnimatePresence 需要包裹被条件渲染的组件,而不是放在组件内部。当你在 Home 中移除 <SideMenu /> 时,组件内部的 AnimatePresence 会被直接销毁,无法触发退出动画。
  2. 过渡动画的属性存在拼写错误(style 应为 type)。
  3. 缺少用于追踪组件的唯一 key 属性。

修正后的代码

1. 调整 SideMenu 组件

移除内部的 AnimatePresence,并修正过渡属性:

import React from "react";
import { motion } from "framer-motion";

const menuItems = ["Home", "Projects", "Blog", "Recipes"];

const menuVariant = {
  hidden: { opacity: 0, x: "-100vw" },
  show: {
    opacity: 1,
    x: 0,
    transition: { type: "tween", duration: 0.75 }, // 修正:style → type
  },
  exit: {
    x: "-100vw",
    opacity: 0, // 添加透明度渐变让退出更平滑
    transition: { ease: "easeInOut", duration: 0.75 },
  },
};

const SideMenu = () => {
  return (
    <motion.div
      className="flex flex-col px-10 bg-orange-400 max-h-full w-2/5 rounded-r-full"
      variants={menuVariant}
      initial="hidden"
      animate="show"
      exit="exit"
    >
      {menuItems.map((item, index) => (
        <button key={index} className="my-3 text-4xl text-left">
          {item}
        </button>
      ))}
    </motion.div>
  );
};

export default SideMenu;

2. 调整 Home 组件

将 AnimatePresence 移到外部包裹条件渲染的 SideMenu,并添加唯一 key:

"use client";
import { motion, AnimatePresence } from "framer-motion";
import { useState } from "react";
import SideMenu from "../components/sideMenu";

const buttonVariant = {
  hidden: { opacity: 0 },
  show: { opacity: 1, transition: { duration: 1, delay: 0.5 } },
};

export default function Home() {
  const [menuState, setMenuState] = useState(false);
  return (
    <>
      <motion.button
        className={`m-10 p-4 border-2 rounded-3xl ${
          menuState ? "border-red-500" : "border-sky-500"
        }`}
        variants={buttonVariant}
        initial="hidden"
        animate="show"
        onClick={() => setMenuState(!menuState)}
      >
        {menuState ? "Close" : "Menu"}
      </motion.button>
      {/* 用 AnimatePresence 包裹条件渲染的菜单 */}
      <AnimatePresence>
        {menuState && <SideMenu key="side-menu" />}
      </AnimatePresence>
    </>
  );
}

关键修复点说明

  • AnimatePresence 的位置:必须直接包裹会被挂载/卸载的组件,这样它才能监听到组件的生命周期变化,触发退出动画。
  • 唯一 key 属性:Framer Motion 需要通过 key 识别组件身份,确保动画能正确触发。
  • 过渡属性修正:style 不是 Framer Motion 过渡的合法属性,改为 type 指定动画类型为 tween。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 23:12:33