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

React Framer-motion AnimatePresence退出动画失效问题排查

页面转场动画仅入场生效,退出动画不执行的解决方案

问题描述

我正在尝试实现页面转场动画,但仅入场动画正常生效。文本可顺利滑入,但路由切换至其他组件时,文本不会执行滑出动画而是直接消失。已尝试为单个组件及Outlet组件分配基于location.pathname的key,也为AnimatePresence添加了exitBeforeEnter与mode="wait"配置,仍无法定位问题所在。

相关代码

主组件

import React from "react";
import Navbar from './navbar.js';
import { Outlet } from "react-router-dom"
import { AnimatePresence } from "framer-motion"
export default function App() {
    return (
      <div>
        <Navbar/>
        <AnimatePresence>
          <Outlet/>
        </AnimatePresence>
      </div>
    );
}

页面组件示例(Section1)

import React from 'react';
import './index.css'
import { motion } from "framer-motion"
import { useLocation } from 'react-router-dom';
export default function Section1() {
  let location = useLocation()
    return (
      <motion.p
      key={location.pathname}
      transition={{duration: 0.8, ease: "easeOut"}}
      initial={{ x: "-100%", opacity: 0 }}
      animate={{ x: 0, opacity: 1 }}
      exit={{ x: "100%", opacity: 0 }} className='text-center text-6xl my-56'>Section 1</motion.p>
    )
}

导航栏组件

import React from "react"
import { Link } from "react-router-dom";
export default function Navbar(router) {
    return (
      <nav className='bg-gray-300 flex items-center justify-between'>
        <p className="ml-6 text-3xl">Варвара Алексеева</p>
        <ul className='flex flex-row justify-end mr-20 text-xl'> 
          <li className='m-4'><Link to={"/"} className='hover:bg-lapis hover:text-white p-2 rounded-xl duration-300'>Main</Link></li>
          <li className='m-4'><Link to={"/section1"} className='hover:bg-lapis hover:text-white p-2 rounded-xl duration-300'>Section 1</Link></li>
          <li className='m-4'><Link to={"/section2"} className='hover:bg-lapis hover:text-white p-2 rounded-xl duration-300'>Section-2 2</Link></li>
          <li className='m-4'><Link to={"/section3"} className='hover:bg-lapis hover:text-white p-2 rounded-xl duration-300'>Section 3</Link></li>
        </ul>
      </nav>
    )
  }

解决方案

核心问题是**AnimatePresence需要通过唯一key识别元素的替换,才能触发退出动画**,之前的写法里Outlet没有绑定路由相关的key,导致路由切换时AnimatePresence无法追踪旧组件的卸载过程。

修改步骤

  1. 为主组件的Outlet添加路由key
    在主组件中引入useLocation获取当前路由信息,给Outlet设置key={location.pathname},同时给AnimatePresence加上exitBeforeEnter确保退出动画完成后再执行入场动画:

    import React from "react";
    import Navbar from './navbar.js';
    import { Outlet, useLocation } from "react-router-dom"
    import { AnimatePresence } from "framer-motion"
    export default function App() {
        const location = useLocation();
        return (
          <div>
            <Navbar/>
            <AnimatePresence exitBeforeEnter>
              <Outlet key={location.pathname}/>
            </AnimatePresence>
          </div>
        );
    }
    
  2. 移除页面组件中多余的key
    页面组件里的motion元素不需要再绑定location.pathname作为key,因为Outlet已经通过key触发了组件的替换,AnimatePresence会自动捕获到exit事件:

    import React from 'react';
    import './index.css'
    import { motion } from "framer-motion"
    export default function Section1() {
        return (
          <motion.p
          transition={{duration: 0.8, ease: "easeOut"}}
          initial={{ x: "-100%", opacity: 0 }}
          animate={{ x: 0, opacity: 1 }}
          exit={{ x: "100%", opacity: 0 }} className='text-center text-6xl my-56'>Section 1</motion.p>
        )
    }
    
  3. 确保所有页面组件的motion元素都配置exit属性
    每个路由对应的页面组件,其根motion元素必须包含exit动画配置,这样AnimatePresence才能正确触发退出动画。

原理说明

AnimatePresence的工作逻辑是:当包裹的子元素发生替换(通过key变化识别)时,先执行旧元素的exit动画,待动画完成后再卸载旧元素并渲染新元素执行入场动画。之前的写法中Outlet没有key,路由切换时AnimatePresence感知不到元素的替换,直接卸载旧组件,因此看不到退出动画。给Outlet绑定路由pathname作为key后,每次路由变化都会触发Outlet的“新旧替换”,AnimatePresence就能按预期执行完整的转场动画。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 03:12:18