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

Framer Motion中如何在组件已渲染时动态修改exit动画参数值

Framer Motion中如何在组件已渲染时动态修改exit动画参数值

嘿,我完全懂你碰到的这个麻烦——当你跨标签页跳转(比如从第2页直接跳到第3页)时,退出的页面动画方向完全不对,因为当前的exit参数是组件渲染时就固定死的,没法跟着新的跳转方向动态更新对吧?我来给你几个实用的解决方案,帮你搞定这个问题:


方案一:拆分「进入方向」和「退出方向」,用AnimatePresence控制时序

你的核心问题在于,现在全局的direction状态既管进入动画又管退出动画,但这两个方向其实是相反的(比如从页1到页2,页1退出方向是-100%,页2进入方向是100%)。我们可以把这两个状态分开:

  1. 修改导航组件的handleChange逻辑:

    const handleChange = (event, newValue) => {
      const oldValue = value;
      // 计算「旧页面的退出方向」:新页面索引更大,旧页面向左退;反之向右退
      const exitDirection = newValue > oldValue ? "-100%" : "100%";
      // 计算「新页面的进入方向」:和退出方向正好相反
      const enterDirection = newValue > oldValue ? "100%" : "-100%";
    
      // 先更新退出方向,让即将卸载的页面拿到正确的exit参数
      setExitDirection(exitDirection);
      // 再更新进入方向,给新页面用
      setDirection(enterDirection);
    
      // 别忘了存到localStorage
      localStorage.setItem("bottomNavSelectedValue", newValue.toString());
      // 最后切换页面值
      setValue(newValue);
    };
    
  2. 用AnimatePresence包裹页面,开启wait模式:
    一定要用AnimatePresence才能让exit动画生效,而且mode="wait"会等旧页面退出动画完成后再加载新页面,避免动画重叠:

    import { AnimatePresence, motion } from "framer-motion";
    
    // 页面容器组件
    const PageContainer = ({ value, direction, exitDirection }) => {
      return (
        <AnimatePresence mode="wait">
          {value === 0 && (
            <motion.div
              className="body"
              initial={{ x: direction }}
              animate={{ x: 0 }}
              exit={{ x: exitDirection }}
              transition={{ duration: 0.2 }}
            >
              {/* 页1内容 */}
            </motion.div>
          )}
          {value === 1 && (
            <motion.div
              className="body"
              initial={{ x: direction }}
              animate={{ x: 0 }}
              exit={{ x: exitDirection }}
              transition={{ duration: 0.2 }}
            >
              {/* 页2内容 */}
            </motion.div>
          )}
          {/* 其他页面同理 */}
        </AnimatePresence>
      );
    };
    

方案二:让每个页面自己计算退出方向(更灵活)

如果不想维护全局的退出方向状态,也可以让每个页面组件根据自身索引和当前选中的索引,自己算出该用什么退出方向:

import { motion, AnimatePresence } from "framer-motion";
import { useEffect, useRef, useState } from "react";

const PageComponent = ({ index, currentIndex }) => {
  const [exitX, setExitX] = useState(0);
  // 用ref保存上一次的选中索引,用来判断当前页面是否要退出
  const prevCurrentIndexRef = useRef(currentIndex);

  useEffect(() => {
    // 当选中索引变化,且之前选中的是当前页面时,计算退出方向
    if (prevCurrentIndexRef.current === index) {
      setExitX(currentIndex > index ? "-100%" : "100%");
    }
    // 更新ref的值
    prevCurrentIndexRef.current = currentIndex;
  }, [currentIndex, index]);

  // 计算进入方向
  const enterDirection = currentIndex > index ? "-100%" : "100%";

  return (
    <motion.div
      className="body"
      initial={{ x: enterDirection }}
      animate={{ x: 0 }}
      exit={{ x: exitX }}
      transition={{ duration: 0.2 }}
    >
      {/* 页面内容 */}
    </motion.div>
  );
};

// 页面容器调用示例
const PageContainer = ({ currentIndex }) => {
  return (
    <AnimatePresence mode="wait">
      <PageComponent index={0} currentIndex={currentIndex} />
      <PageComponent index={1} currentIndex={currentIndex} />
      <PageComponent index={2} currentIndex={currentIndex} />
    </AnimatePresence>
  );
};

这种方式不需要全局维护方向状态,每个页面自己处理动画逻辑,跨标签跳转时也能精准计算退出方向。


关键注意点

  • 必须用AnimatePresence包裹动态切换的组件,否则Framer Motion的exit动画不会触发;
  • mode="wait"是核心,它能确保旧页面完全退出后再加载新页面,避免动画混乱;
  • 不要把进入方向和退出方向混为一谈,两者在跨页跳转时是相反的,必须分开处理。

备注:内容来源于stack exchange,提问作者stevenyoussef

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 07:54:30