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

如何在Framer Motion动画完成后触发CSS动画?

解决方案:Framer Motion动画完成后触发CSS动画

完全可行,Framer Motion自带onAnimationComplete回调机制,能精准捕获父元素动画结束的时机,再触发子组件的CSS动画,彻底解决时机偏差问题。下面给两种实用实现方案:

方案一:直接用motion元素的回调函数

修改父组件的motion.section,添加动画完成回调,通过状态通知子组件触发动画:

import { useState } from 'react';
import { motion } from 'framer-motion';

// 父组件
function ParentComponent() {
  const [parentAnimDone, setParentAnimDone] = useState(false);

  return (
    <motion.section
      initial={{ x: 100, opacity: 0 }}
      animate={{ x: 0, opacity: 1 }}
      transition={{ when: 'beforeChildren'}}
      // 动画完成后更新状态
      onAnimationComplete={() => setParentAnimDone(true)}
    >
      <MyComponent triggerAnim={parentAnimDone} />
    </motion.section>
  );
}

然后修改MyComponent,依赖传入的状态触发CSS动画:

const MyComponent = ({ triggerAnim }) => {
  useEffect(() => {
    // 仅当父组件动画完成时执行
    if (triggerAnim) {
      const id = getFromUrl();
      const targetEl = document.getElementById(id);
      if (targetEl) {
        targetEl.classList.add('purple-highlight');
      }
    }
  }, [triggerAnim]) // 监听状态变化

  // ... 组件其余代码 ...
}

方案二:用useAnimation钩子(更灵活)

如果需要更精细控制动画流程,比如手动触发父组件动画,可以用Framer Motion的useAnimation钩子:

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

function ParentComponent() {
  const animControls = useAnimation();
  const [parentAnimDone, setParentAnimDone] = useState(false);

  useEffect(() => {
    const runAnim = async () => {
      // 等待父组件动画执行完成
      await animControls.start({ x: 0, opacity: 1 });
      setParentAnimDone(true);
    };
    runAnim();
  }, [animControls]);

  return (
    <motion.section
      initial={{ x: 100, opacity: 0 }}
      animate={animControls}
      transition={{ when: 'beforeChildren'}}
    >
      <MyComponent triggerAnim={parentAnimDone} />
    </motion.section>
  );
}

MyComponent的修改和方案一一致,通过triggerAnim状态触发CSS动画。

额外优化建议

  • 替换DOM操作:用React的useRef获取目标元素,比document.getElementById更符合React范式:
const MyComponent = ({ triggerAnim }) => {
  const targetRef = useRef(null);

  useEffect(() => {
    if (triggerAnim && targetRef.current) {
      targetRef.current.classList.add('purple-highlight');
    }
  }, [triggerAnim])

  return (
    <div>
      {/* 给目标元素绑定ref */}
      <div ref={targetRef} id={getFromUrl()}>需要高亮的元素</div>
      {/* ... */}
    </div>
  );
}
  • 保留CSS中的animation-iteration-count: 1,确保动画只执行一次,避免不必要的循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 12:22:17