如何在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
相关产品推荐
相关产品推荐

