如何使用Framer Motion让SVG对象沿路径移动?
实现SVG对象沿Path路径移动的Framer Motion方案
核心思路
利用Framer Motion的offsetPath和offsetDistance属性控制对象沿路径移动,结合SVG原生API计算路径切线角度,让对象移动时自动对齐路径方向,实现自然的行进效果。
完整代码示例
import { motion, useAnimationFrame, useMotionValue } from "framer-motion"; import { useRef, useEffect } from "react"; export default function PathAnimation() { const pathRef = useRef(null); const totalPathLength = useMotionValue(0); const objectRotation = useMotionValue(0); // 初始化获取路径总长度 useEffect(() => { if (pathRef.current) { totalPathLength.set(pathRef.current.getTotalLength()); } }, []); // 实时计算对象旋转角度,对齐路径切线方向 useAnimationFrame(() => { if (!pathRef.current) return; // 根据当前偏移量获取路径上的点 const currentOffset = totalPathLength.get() * (objectRotation.get() / 100); const currentPoint = pathRef.current.getPointAtLength(currentOffset); const nextPoint = pathRef.current.getPointAtLength(currentOffset + 1); if (currentPoint && nextPoint) { // 计算切线角度并设置旋转值 const angle = Math.atan2(nextPoint.y - currentPoint.y, nextPoint.x - currentPoint.x) * (180 / Math.PI); objectRotation.set(angle); } }); return ( <svg width="800" height="400" viewBox="0 0 800 400"> {/* 参考路径 */} <path ref={pathRef} d="M50,200 C150,100 250,300 350,200 C450,100 550,300 650,200" fill="none" stroke="#ccc" strokeWidth="2" /> {/* 沿路径移动的对象(可替换为自定义SVG图形) */} <motion.circle cx="0" cy="0" r="15" fill="#ff4081" animate={{ offsetDistance: ["0%", "100%"] }} transition={{ duration: 5, repeat: Infinity, ease: "linear" }} style={{ offsetPath: `path("${pathRef.current?.getAttribute("d")}")`, rotate: objectRotation, transformOrigin: "center" }} /> </svg> ); }
关键细节说明
- 路径绑定:通过
offsetPath将对象与目标路径关联,直接复用路径的d属性值即可。 - 路径移动控制:
offsetDistance从0%到100%的动画,对应对象沿路径从起点走到终点。 - 方向对齐:利用
getPointAtLength()获取路径上相邻两点的坐标,计算切线角度后设置对象旋转,保证移动方向与路径一致。 - 自定义对象适配:如果需要使用自定义SVG图形(比如图标、复杂路径),只需将
<motion.circle>替换为<motion.g>或<motion.path>,保留style中的属性即可。 - 动画参数调整:修改
transition中的duration可以控制移动速度,移除repeat: Infinity可让动画只播放一次。
内容的提问来源于stack exchange,提问作者Sayedul Karim
相关产品推荐
相关产品推荐

