基于Framer Motion的SVG动画开发求助:实现曲线灰线与蓝色小球流动
解决方案
一、创建SVG弯曲线条
替换原代码中的<line>为<path>,通过SVG路径指令绘制弧形:
M x,y:定义路径起点Q cx,cy x,y:二次贝塞尔曲线(适配简单弧形)C cx1,cy1 cx2,cy2 x,y:三次贝塞尔曲线(适配复杂曲线)
根据目标布局,用二次贝塞尔拟合上下两组弧形路径即可匹配需求。
二、实现蓝色小球沿路径无限流动
利用Framer Motion的路径动画能力,为每个路径绑定蓝色小球,通过pathOffset属性控制小球沿路径移动,设置统一的无限循环线性动画保证所有小球同步流动。
完整代码示例
import { motion } from "framer-motion"; const Comp = () => { // 统一动画配置:所有小球同步匀速循环 const ballVariants = { flow: { pathOffset: 0, transition: { repeat: Infinity, duration: 2, ease: "linear", }, }, }; return ( <svg width="800" height="800" viewBox="0 0 200 200" className="rotate-90"> {/* 中心U形区域 */} <path d="M 80 100 L 120 100 L 120 110 L 80 110 Z" fill="#3D414899" /> {/* 下方弧形路径组(灰色静态)+ 蓝色小球 */} <path d="M 100 100 Q 70 140 52 175" stroke="#3D414899" strokeWidth="1" fill="none" /> <motion.circle variants={ballVariants} initial={{ pathOffset: 1 }} animate="flow" cx={0} cy={0} r="3" fill="#00A3FF" style={{ pathLength: "path('M 100 100 Q 70 140 52 175')" }} /> <path d="M 100 100 Q 85 145 76 174" stroke="#3D414899" strokeWidth="1" fill="none" /> <motion.circle variants={ballVariants} initial={{ pathOffset: 1 }} animate="flow" cx={0} cy={0} r="3" fill="#00A3FF" style={{ pathLength: "path('M 100 100 Q 85 145 76 174')" }} /> <path d="M 100 100 L 100 174" stroke="#3D414899" strokeWidth="1" fill="none" /> <motion.circle variants={ballVariants} initial={{ pathOffset: 1 }} animate="flow" cx={0} cy={0} r="3" fill="#00A3FF" style={{ pathLength: "path('M 100 100 L 100 174')" }} /> <path d="M 100 100 Q 115 145 126 180" stroke="#3D414899" strokeWidth="1" fill="none" /> <motion.circle variants={ballVariants} initial={{ pathOffset: 1 }} animate="flow" cx={0} cy={0} r="3" fill="#00A3FF" style={{ pathLength: "path('M 100 100 Q 115 145 126 180')" }} /> <path d="M 100 100 Q 130 140 147 168" stroke="#3D414899" strokeWidth="1" fill="none" /> <motion.circle variants={ballVariants} initial={{ pathOffset: 1 }} animate="flow" cx={0} cy={0} r="3" fill="#00A3FF" style={{ pathLength: "path('M 100 100 Q 130 140 147 168')" }} /> {/* 上方弧形路径组(灰色静态)+ 蓝色小球 */} <path d="M 100 100 Q 130 60 148 25" stroke="#3D414899" strokeWidth="1" fill="none" /> <motion.circle variants={ballVariants} initial={{ pathOffset: 1 }} animate="flow" cx={0} cy={0} r="3" fill="#00A3FF" style={{ pathLength: "path('M 100 100 Q 130 60 148 25')" }} /> <path d="M 100 100 Q 115 60 124 26" stroke="#3D414899" strokeWidth="1" fill="none" /> <motion.circle variants={ballVariants} initial={{ pathOffset: 1 }} animate="flow" cx={0} cy={0} r="3" fill="#00A3FF" style={{ pathLength: "path('M 100 100 Q 115 60 124 26')" }} /> <path d="M 100 100 L 100 26" stroke="#3D414899" strokeWidth="1" fill="none" /> <motion.circle variants={ballVariants} initial={{ pathOffset: 1 }} animate="flow" cx={0} cy={0} r="3" fill="#00A3FF" style={{ pathLength: "path('M 100 100 L 100 26')" }} /> <path d="M 100 100 Q 85 60 74 20" stroke="#3D414899" strokeWidth="1" fill="none" /> <motion.circle variants={ballVariants} initial={{ pathOffset: 1 }} animate="flow" cx={0} cy={0} r="3" fill="#00A3FF" style={{ pathLength: "path('M 100 100 Q 85 60 74 20')" }} /> <path d="M 100 100 Q 70 60 55 27" stroke="#3D414899" strokeWidth="1" fill="none" /> <motion.circle variants={ballVariants} initial={{ pathOffset: 1 }} animate="flow" cx={0} cy={0} r="3" fill="#00A3FF" style={{ pathLength: "path('M 100 100 Q 70 60 55 27')" }} /> </svg> ); }; export default Comp;
关键说明
- 弯曲线条调整:可修改
<path>中Q后的中间控制点坐标,微调弧形弧度以完全匹配目标图。 - 动画同步性:所有小球共用同一动画配置,确保流动节奏完全一致;
linear缓动保证匀速运动。 - 循环逻辑:
pathOffset从1(路径终点)过渡到0(路径起点),配合无限循环实现往返流动效果。
内容的提问来源于stack exchange,提问作者Govind ganeriwal
相关产品推荐
相关产品推荐

