You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Framer Motion中SVG pathLength异常:pathLength=1未对应完整路径

解决Framer Motion中多路径SVG的pathLength动画失效问题

问题原因

你当前使用的SVG path 是多条子路径合并的(d 属性包含多个 M 起始命令),而Framer Motion的 pathLength 属性默认针对单一路径设计。这种情况下,pathLength 的值无法正确映射到所有子路径的总长度,导致设置 pathLength: 0.5 时仍显示完整路径。

解决方案

方案1:拆分多路径为独立的motion.path元素

把原合并的路径拆分成多个单独的 <motion.path>,让每个子路径都能独立应用 pathLength 动画:

const handleSvg = async () => {
  const svgDrawDuration = 3;
  const svgFadeInOutDuration = 0.5;
  const timeUntilVisible = 1.5;
  const repeatDelay = 1;

  // 批量给所有路径设置动画
  const animatePaths = (props, options) => {
    document.querySelectorAll('.svg-path').forEach(path => {
      startSvg(path, props, options);
    });
  };

  animatePaths({ strokeOpacity: 1 }, { duration: svgFadeInOutDuration, delay: timeUntilVisible });
  await animatePaths({ pathLength: 1 }, { duration: svgDrawDuration, ease: 'easeInOut', delay: timeUntilVisible });

  animatePaths({ strokeOpacity: 0 }, { duration: svgFadeInOutDuration, delay: (svgDrawDuration - svgFadeInOutDuration) + repeatDelay });
  await animatePaths({ pathLength: 0 }, { duration: svgDrawDuration, ease: "easeInOut", delay: repeatDelay });
  
  setTimeout(() => handleSvg(), 500);
}

// 拆分后的SVG结构
<svg ref={scope} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <motion.path className="svg-path svgAnimation"
    initial={{ strokeOpacity: 0, pathLength: 0 }}
    strokeLinecap="round" strokeLinejoin="round"
    d="M10.5 6h9.75" />
  <motion.path className="svg-path svgAnimation"
    initial={{ strokeOpacity: 0, pathLength: 0 }}
    strokeLinecap="round" strokeLinejoin="round"
    d="M10.5 6a1.5 1.5 0 1 1-3 0" />
  <motion.path className="svg-path svgAnimation"
    initial={{ strokeOpacity: 0, pathLength: 0 }}
    strokeLinecap="round" strokeLinejoin="round"
    d="m3 6a1.5 1.5 0 1 0-3 0" />
  <motion.path className="svg-path svgAnimation"
    initial={{ strokeOpacity: 0, pathLength: 0 }}
    strokeLinecap="round" strokeLinejoin="round"
    d="M3.75 6H7.5" />
  <motion.path className="svg-path svgAnimation"
    initial={{ strokeOpacity: 0, pathLength: 0 }}
    strokeLinecap="round" strokeLinejoin="round"
    d="m13.5 18h9.75" />
  <motion.path className="svg-path svgAnimation"
    initial={{ strokeOpacity: 0, pathLength: 0 }}
    strokeLinecap="round" strokeLinejoin="round"
    d="M10.5 18a1.5 1.5 0 0 1-3 0" />
  <motion.path className="svg-path svgAnimation"
    initial={{ strokeOpacity: 0, pathLength: 0 }}
    strokeLinecap="round" strokeLinejoin="round"
    d="m7.5 18a1.5 1.5 0 0 0-3 0" />
  <motion.path className="svg-path svgAnimation"
    initial={{ strokeOpacity: 0, pathLength: 0 }}
    strokeLinecap="round" strokeLinejoin="round"
    d="M3.75 18H7.5" />
  <motion.path className="svg-path svgAnimation"
    initial={{ strokeOpacity: 0, pathLength: 0 }}
    strokeLinecap="round" strokeLinejoin="round"
    d="m22.5 12h3.75" />
  <motion.path className="svg-path svgAnimation"
    initial={{ strokeOpacity: 0, pathLength: 0 }}
    strokeLinecap="round" strokeLinejoin="round"
    d="M19.5 12a1.5 1.5 0 0 1-3 0" />
  <motion.path className="svg-path svgAnimation"
    initial={{ strokeOpacity: 0, pathLength: 0 }}
    strokeLinecap="round" strokeLinejoin="round"
    d="m16.5 12a1.5 1.5 0 0 0-3 0" />
  <motion.path className="svg-path svgAnimation"
    initial={{ strokeOpacity: 0, pathLength: 0 }}
    strokeLinecap="round" strokeLinejoin="round"
    d="M3.75 12h9.75" />
</svg>

方案2:使用strokeDasharray + strokeDashoffset替代pathLength

对于多路径,传统描边动画方式更可靠,通过动画 strokeDashoffset 实现绘制效果:

import { useRef, useEffect } from 'react';
import { motion, useAnimation } from 'framer-motion';

const SvgAnimation = () => {
  const pathRef = useRef(null);
  const controls = useAnimation();

  useEffect(() => {
    const path = pathRef.current;
    if (!path) return;

    // 获取路径总长度
    const totalLength = path.getTotalLength();

    const handleAnimation = async () => {
      const svgDrawDuration = 3;
      const svgFadeInOutDuration = 0.5;
      const timeUntilVisible = 1.5;
      const repeatDelay = 1;

      // 初始状态:完全隐藏描边
      await controls.start({
        strokeOpacity: 0,
        strokeDasharray: totalLength,
        strokeDashoffset: totalLength,
      });

      // 显示描边并开始绘制
      await controls.start({
        strokeOpacity: 1,
        transition: { duration: svgFadeInOutDuration, delay: timeUntilVisible }
      });
      await controls.start({
        strokeDashoffset: 0,
        transition: { duration: svgDrawDuration, ease: 'easeInOut', delay: timeUntilVisible }
      });

      // 隐藏描边并反向绘制
      await controls.start({
        strokeOpacity: 0,
        transition: { duration: svgFadeInOutDuration, delay: (svgDrawDuration - svgFadeInOutDuration) + repeatDelay }
      });
      await controls.start({
        strokeDashoffset: totalLength,
        transition: { duration: svgDrawDuration, ease: 'easeInOut', delay: repeatDelay }
      });

      setTimeout(handleAnimation, 500);
    };

    handleAnimation();
  }, [controls]);

  return (
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
      <motion.path
        ref={pathRef}
        className={styles.svgAnimation}
        strokeLinecap="round" strokeLinejoin="round"
        d="M10.5 6h9.75M10.5 6a1.5 1.5 0 1 1-3 0m3 0a1.5 1.5 0 1 0-3 0M3.75 6H7.5m3 12h9.75m-9.75 0a1.5 1.5 0 0 1-3 0m3 0a1.5 1.5 0 0 0-3 0m-3.75 0H7.5m9-6h3.75m-3.75 0a1.5 1.5 0 0 1-3 0m3 0a1.5 1.5 0 0 0-3 0m-9.75 0h9.75"
        animate={controls}
      />
    </svg>
  );
};

额外注意事项

  • 确保 svgAnimation CSS类设置了stroke宽度(比如 stroke-width: 2),否则描边可能不可见。
  • 当前示例是纯线条动画,建议给路径添加 fill: none,不需要的话可以移除 fillOpacity 相关动画。

内容的提问来源于stack exchange,提问作者Randomguy660

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 11:27:08