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

React Spring:如何在父组件过渡完成后触发子组件动画链式调用?

如何让组件内部动画在页面过渡动画完成后执行?

这个场景我太熟悉了——当页面级过渡和组件内部动画撞在一起,又没法直接用useChain(毕竟不在同一个组件树层级),确实头疼。给你几个经过实践验证的解决方案,按你的技术栈选就行:

方案1:状态传递 + 动画完成回调(最通用)

核心思路是在页面过渡的根组件里监听动画完成事件,把“过渡已完成”的状态传递给子组件,子组件只在这个状态为true时触发内部动画。

示例代码:

首先在App层维护状态并传递:

import { useState } from 'react';
import { motion } from 'framer-motion';
import { Switch, Route } from 'react-router-dom';
import LandingPage from './LandingPage';

function App() {
  // 标记页面过渡是否完成
  const [isPageTransitionDone, setIsPageTransitionDone] = useState(false);

  return (
    // 页面过渡容器
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      exit={{ opacity: 0, y: -20 }}
      // 动画完成时更新状态
      onComplete={() => setIsPageTransitionDone(true)}
      // 路由切换时重置状态,避免下次进入直接触发内部动画
      key={window.location.pathname}
    >
      <Switch>
        <Route 
          path="/landing" 
          render={() => <LandingPage isPageReady={isPageTransitionDone} />} 
        />
        {/* 其他路由组件 */}
      </Switch>
    </motion.div>
  );
}

然后在LandingPage里根据状态触发内部动画:

import { useEffect } from 'react';
import { motion, useAnimation } from 'framer-motion';

function LandingPage({ isPageReady }) {
  const internalControls = useAnimation();

  useEffect(() => {
    // 只有页面过渡完成后,才启动内部多阶段动画
    if (isPageReady) {
      internalControls.start([
        { opacity: 0, scale: 0.8 },
        { opacity: 1, scale: 1 },
        { rotate: 5 },
        { rotate: 0 }
        // 更多动画阶段...
      ]);
    }
  }, [isPageReady, internalControls]);

  return (
    <motion.div animate={internalControls} initial={{ opacity: 0 }}>
      {/* 你的组件内容 */}
      <h1>欢迎来到首页</h1>
      <p>这是内部动画演示</p>
    </motion.div>
  );
}

方案2:用Context共享动画状态(适合多组件需要同步的场景)

如果多个页面组件都需要等待页面过渡完成,用Context把状态全局共享会更方便,不用一个个传props。

示例代码:

先创建动画上下文:

// AnimationContext.js
import { createContext, useContext } from 'react';

const AnimationContext = createContext({
  isPageTransitionDone: false,
});

export const useAnimationContext = () => useContext(AnimationContext);
export default AnimationContext;

然后在App层提供上下文:

import { useState, useEffect } from 'react';
import { motion, useAnimation } from 'framer-motion';
import { Switch, Route, useLocation } from 'react-router-dom';
import AnimationContext from './AnimationContext';
import LandingPage from './LandingPage';

function App() {
  const location = useLocation();
  const pageControls = useAnimation();
  const [isPageTransitionDone, setIsPageTransitionDone] = useState(false);

  // 监听页面过渡动画的完成事件
  useEffect(() => {
    const unsubscribe = pageControls.on('animationComplete', () => {
      setIsPageTransitionDone(true);
    });
    // 路由切换时重置状态
    setIsPageTransitionDone(false);
    // 启动页面过渡动画
    pageControls.start({ opacity: 1, y: 0 });
    return unsubscribe;
  }, [location.pathname, pageControls]);

  return (
    <AnimationContext.Provider value={{ isPageTransitionDone }}>
      <motion.div
        initial={{ opacity: 0, y: 20 }}
        animate={pageControls}
        exit={{ opacity: 0, y: -20 }}
      >
        <Switch location={location} key={location.pathname}>
          <Route path="/landing" component={LandingPage} />
        </Switch>
      </motion.div>
    </AnimationContext.Provider>
  );
}

最后在LandingPage里消费上下文:

import { useEffect } from 'react';
import { motion, useAnimation } from 'framer-motion';
import { useAnimationContext } from './AnimationContext';

function LandingPage() {
  const { isPageTransitionDone } = useAnimationContext();
  const internalControls = useAnimation();

  useEffect(() => {
    if (isPageTransitionDone) {
      internalControls.start({/* 你的内部动画序列 */});
    }
  }, [isPageTransitionDone, internalControls]);

  return <motion.div animate={internalControls}>...</motion.div>;
}

关键注意点

  • 记得路由切换时重置状态:不然用户从其他页面回到LandingPage时,isPageTransitionDone还是true,内部动画不会重新触发。
  • 如果用AnimatePresence处理路由切换的退出+进入动画,建议监听onExitComplete事件(旧页面退出完成后)再触发新页面的内部动画,体验更流畅。

内容的提问来源于stack exchange,提问作者Z.M

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 16:43:02