使用Framer Motion的AnimatePresence实现侧边菜单退出动画失效问题
问题分析与解决方案
你的侧边菜单退出动画不生效的核心原因是 AnimatePresence 的位置错误,以及几处小的代码问题:
AnimatePresence需要包裹被条件渲染的组件,而不是放在组件内部。当你在Home中移除<SideMenu />时,组件内部的AnimatePresence会被直接销毁,无法触发退出动画。- 过渡动画的属性存在拼写错误(
style应为type)。 - 缺少用于追踪组件的唯一
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
相关产品推荐
相关产品推荐

