在 React 中使用 framer motion 动画 svg 文本

Animating svg text using framer motion in React

我想使用 Framer Motion 在 React 中为 svg 文本的字母轮廓设置动画,这样线条从特定点开始,然后在一段时间内逐渐完成。我有以下示例代码

import { useState, useRef, useEffect } from "react";
import { motion } from "framer-motion";
import "./styles.css";

export default function App() {
  const [letterLength, setLetterLength] = useState(0);
  const letterRef = useRef();

  useEffect(() => {
    setLetterLength(letterRef.current.getTotalLength());
  }, []);

  return (
    <svg
      id="logo"
      width="998"
      height="108"
      viewBox="0 0 998 108"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <mask
        id="path-1-outside-1"
        maskUnits="userSpaceOnUse"
        x="0.867188"
        y="0.21875"
        width="998"
        height="108"
        fill="black"
      >
        <rect fill="white" x="0.867188" y="0.21875" width="998" height="108" />
        <path d="M15.3672 105H1.86719V2.625H15.3672V105Z" />
      </mask>
      <motion.path
        initial={{
          strokeDasharray: letterLength,
          strokeDashoffset: letterLength
        }}
        animate={{
          strokeDasharray: letterLength,
          strokeDashoffset: 0
        }}
        transition={{ duration: 2 }}
        d="M15.3672 105H1.86719V2.625H15.3672V105Z"
        stroke="#EAE3DC"
        strokeWidth="2"
        mask="url(#path-1-outside-1)"
        ref={letterRef}
      />
    </svg>
  );
}

但是上面的代码表现得很奇怪。似乎这条线在我不想要的预期结果之前被多次动画化。使用 vanilla JS 和 CSS 为字母制作动画时,我没有遇到这个问题。我认为问题与状态变量有关,但我不确定它到底是什么。

这是 codesandbox 上的代码。

奇怪的是被动画化的破折号数组的大小。我不认为这是你的意图,但 letterLength 初始化为 0,然后在第二次渲染时更改为 230。

我通过将 letterLength 设置为常量值发现了这一点。

我建议不要在这里乱用 refs 而只使用百分比

      <motion.path
        initial={{
          strokeDasharray: "100%",
          strokeDashoffset: "100%"
        }}
        animate={{
          strokeDashoffset: "0%"
        }}
        transition={{ duration: 2 }}
        d="M15.3672 105H1.86719V2.625H15.3672V105Z"
        stroke="#EAE3DC"
        strokeWidth="2"
        mask="url(#path-1-outside-1)"
      />

像这样:https://codesandbox.io/s/framer-motion-animate-stroke-with-dasharrayoffset-ezyuj?file=/src/App.js

注意:我还没有找到一种在动画中使用引用的好方法,而不仅仅是在引用初始化期间隐藏具有不透明度的元素。如果您发现有关该主题的任何内容,请告诉我

** 当天晚些时候编辑:**

您也可以将 pathLength 设置为 100,以便提前知道长度。

        <motion.path
          // this line is the important part
          pathLength={100}
          initial={{
            strokeDasharray: 100,
            strokeDashoffset: 100
          }}
          animate={{
            strokeDashoffset: 0
          }}
          transition={{ duration: 2 }}
          d="M15.3672 105H1.86719V2.625H15.3672V105Z"
          stroke="#aceca1"
          strokeWidth="2"
          mask="url(#path-1-outside-1)"
        />

感谢@kirdes https://discordapp.com/channels/341919693348536320/716908973713784904/855851823578218507