我还不相信offset-path
在Safari上能正常工作,所以我能够使用Framer Motion的useMotionValue
hook来实现这个功能。
首先,我们获取进度路径的总长度。然后,我们从运动监听器中获取起始路径长度。这是从0开始的。
现在,我们将起始长度(0)与总路径长度相乘,以获取圆形的起始X和Y坐标。
ProgressX和ProgressY与圆的中心相关联。
在这种情况下,它应该将我们的圆放置在路径的起点处。
以这种方式进行操作允许圆从任何距离开始,通过修改运动监听器的初始值。
然后,只需监听progressLength的更新,并在其更改时更新圆的中心即可。
import { motion, useMotionValue } from "framer-motion";
import { useRef, useEffect } from "react";
export default function App() {
const pathRefForeground = useRef(null);
const progressLength = useMotionValue(0);
const progressX = useMotionValue(0);
const progressY = useMotionValue(0);
useEffect(() => {
const pathElementForeground = pathRefForeground.current;
const totalPathLength = pathElementForeground.getTotalLength();
const initialProgress = progressLength.get();
const initialCoords = pathElementForeground.getPointAtLength(
initialProgress * totalPathLength
);
progressX.set(initialCoords.x);
progressY.set(initialCoords.y);
const unsubscribe = progressLength.onChange((latestPercent) => {
const latestPathProgress = pathElementForeground.getPointAtLength(
latestPercent * totalPathLength
);
progressX.set(latestPathProgress.x);
progressY.set(latestPathProgress.y);
});
return unsubscribe;
}, []);
const transition = {
repeat: Infinity,
bounce: 0.75,
type: "spring",
duration: 2
};
const progress = 50;
return (
<div
className="App"
style={{
minHeight: 500,
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
background: "#d9eefd"
}}
>
<motion.svg width="500" height="50" viewBox="0 0 500 30">
<path
stroke="white"
strokeWidth="10"
strokeLinecap="round"
d="M15 15 H490"
/>
<motion.path
d="M15 15 H490"
stroke="#1f88eb"
strokeWidth="10"
strokeLinecap="round"
ref={pathRefForeground}
pathLength={progressLength}
initial={{ pathLength: 0 }}
animate={{ pathLength: progress / 100 }}
transition={transition}
/>
<motion.circle cx={progressX} cy={progressY} r="15" fill="#1f88eb" />
<motion.circle cx={progressX} cy={progressY} r="5" fill="white" />
</motion.svg>
</div>
);
}
这是一个实时演示:
https://codesandbox.io/s/patient-sea-nbhs5u?file=/src/App.js