在 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
我想使用 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