React中如何控制Framer Motion等动画播放暂停,适配视频同步需求
React中视频与叠加动画同步控制的实现方案
核心逻辑为监听video元素的play/pause事件,同步修改动画的播放状态,完全在前端运行时控制,无需修改视频源文件,符合不使用FFmpeg的要求。
方案1:Framer Motion实现
- 核心使用
useAnimation钩子获取动画控制实例,调用对应方法即可实现播放、暂停控制 - 代码示例:
import { useRef, useEffect } from 'react'; import { motion, useAnimation } from 'framer-motion'; function VideoWithOverlay() { const videoRef = useRef(null); const controls = useAnimation(); useEffect(() => { const video = videoRef.current; if (!video) return; const handlePlay = () => controls.start(); // Framer Motion v7+ 可替换为controls.pause()实现从暂停位置续播 const handlePause = () => controls.stop(); video.addEventListener('play', handlePlay); video.addEventListener('pause', handlePause); return () => { video.removeEventListener('play', handlePlay); video.removeEventListener('pause', handlePause); }; }, [controls]); return ( <div style={{ position: 'relative', width: '800px' }}> <video ref={videoRef} controls style={{ width: '100%' }}> <source src="你的视频地址" type="video/mp4" /> </video> {/* 叠加动画元素示例 */} <motion.div style={{ position: 'absolute', top: '20%', left: '30%', width: '50px', height: '50px', borderRadius: '50%', background: 'rgba(255,255,255,0.7)', }} animate={controls} variants={{ start: { y: [0, -30, 0], opacity: [0.7, 1, 0.7], transition: { repeat: Infinity, duration: 2, ease: 'easeInOut' } } }} /> </div> ); }
方案2:GSAP实现
- GSAP的补间动画/时间线实例原生支持
play()/pause()方法,控制粒度更细,适合复杂多元素动画场景 - 代码示例:
import { useRef, useEffect } from 'react'; import gsap from 'gsap'; function VideoWithOverlay() { const videoRef = useRef(null); const animRef = useRef(null); const tlRef = useRef(null); useEffect(() => { // 初始化循环动画时间线,默认暂停 tlRef.current = gsap.timeline({ repeat: -1, paused: true }) .to(animRef.current, { y: -30, opacity: 1, duration: 1, ease: 'power1.inOut' }) .to(animRef.current, { y: 0, opacity: 0.7, duration: 1, ease: 'power1.inOut' }); const video = videoRef.current; if (!video) return; const handlePlay = () => tlRef.current.play(); const handlePause = () => tlRef.current.pause(); video.addEventListener('play', handlePlay); video.addEventListener('pause', handlePause); return () => { video.removeEventListener('play', handlePlay); video.removeEventListener('pause', handlePause); tlRef.current.kill(); // 销毁动画避免内存泄漏 }; }, []); return ( <div style={{ position: 'relative', width: '800px' }}> <video ref={videoRef} controls style={{ width: '100%' }}> <source src="你的视频地址" type="video/mp4" /> </video> <div ref={animRef} style={{ position: 'absolute', top: '20%', left: '30%', width: '50px', height: '50px', borderRadius: '50%', background: 'rgba(255,255,255,0.7)', opacity: 0.7 }} /> </div> ); }
方案3:Lottie实现
如果使用设计师导出的JSON格式动效,Lottie是最优选择,lottie-react库原生支持播放暂停控制
- 代码示例:
import { useRef, useEffect } from 'react'; import Lottie from 'lottie-react'; import animationData from './你的动效文件.json'; function VideoWithOverlay() { const videoRef = useRef(null); const lottieRef = useRef(null); useEffect(() => { const video = videoRef.current; if (!video) return; const handlePlay = () => lottieRef.current?.play(); const handlePause = () => lottieRef.current?.pause(); video.addEventListener('play', handlePlay); video.addEventListener('pause', handlePause); return () => { video.removeEventListener('play', handlePlay); video.removeEventListener('pause', handlePause); }; }, []); return ( <div style={{ position: 'relative', width: '800px' }}> <video ref={videoRef} controls style={{ width: '100%' }}> <source src="你的视频地址" type="video/mp4" /> </video> <div style={{ position: 'absolute', top: '20%', left: '30%', width: '100px' }}> <Lottie lottieRef={lottieRef} animationData={animationData} loop={true} autoplay={false} // 关闭自动播放,由视频状态控制 /> </div> </div> ); }
内容的提问来源于stack exchange,提问作者Mila A
相关产品推荐
相关产品推荐

