Anime.js 超级炫酷的网页动画库之SVG路径动画
简介
Anime.js 是一个强大且易用的 JavaScript 动画库,支持对 DOM、SVG、CSS 属性等多种对象进行高性能动画处理。它拥有丰富的缓动函数、时间线控制、序列动画、SVG 路径动画等特性,适用于网页交互动效、数据可视化、图标动画等多种场景。通过 Anime.js,你可以用极简的代码实现复杂的动画效果,提升网页的视觉表现力和用户体验。
安装
npm install animejs
Anime.js 也可以非常方便地为 SVG 元素添加动画,支持路径、形状、颜色等多种属性的动画。下面是一个 SVG 路径动画的示例:
示例
SVG 方 → 星
import { useEffect, useRef } from "react";
import { animate } from "animejs";const points = 16;
const radius = 70;
const center = 100;// 生成圆
function getCircle() {return Array.from({ length: points }, (_, i) => {const angle = (2 * Math.PI * i) / points - Math.PI / 2;return [center + radius * Math.cos(angle),center + radius * Math.sin(angle),];});
}// 生成“圆角方形”,点分布和圆一致,只是半径在四个角缩小
function getSquare() {return Array.from({ length: points }, (_, i) => {const angle = (2 * Math.PI * i) / points - Math.PI / 2;// 0,4,8,12是边的中点,其他是角const isCorner = i % 4 !== 0;const r = isCorner ? radius * 0.55 : radius;return [center + r * Math.cos(angle), center + r * Math.sin(angle)];});
}// 生成星形
function getStar() {const r1 = radius;const r2 = radius * 0.45;return Array.from({ length: points }, (_, i) => {const angle = (2 * Math.PI * i) / points - Math.PI / 2;const r = i % 2 === 0 ? r1 : r2;return [center + r * Math.cos(angle), center + r * Math.sin(angle)];});
}// 转换为 path 字符串
function toPath(pointsArr) {return ("M" +pointsArr.map(([x, y]) => `${x.toFixed(2)},${y.toFixed(2)}`).join(" L ") +" Z");
}const shapes = [toPath(getCircle()), toPath(getSquare()), toPath(getStar())];export default function ShapeMorphDemo() {const shapeRef = useRef(null);const current = useRef(0);useEffect(() => {let running = true;const morph = () => {if (!running) return;const from = shapes[current.current % shapes.length];const to = shapes[(current.current + 1) % shapes.length];animate(shapeRef.current, {d: [from, to],duration: 2200,ease: "outElastic(1, .7)",complete: () => {current.current = (current.current + 1) % shapes.length;setTimeout(morph, 600);},});};morph();return () => {running = false;};}, []);return (<div className="flex flex-col items-center justify-center min-h-[60vh]"><svg width="200" height="200" viewBox="0 0 200 200"><pathref={shapeRef}d={shapes[0]}fill="#60a5fa"stroke="#1e3a8a"strokeWidth="4"/></svg><div className="mt-6 text-lg text-gray-700">方 → 星</div></div>);
}
SVG 圆 ↔ 心形
import { useEffect, useRef, useState } from "react";
import { animate } from "animejs";const points = 80;
const radius = 70;
const center = 100;// 标准圆
function getCircle() {return Array.from({ length: points }, (_, i) => {const angle = (2 * Math.PI * i) / points;return [center + radius * Math.cos(angle),center + radius * Math.sin(angle),];});
}// 标准心形
function getHeart() {return Array.from({ length: points }, (_, i) => {const t = (2 * Math.PI * i) / points;const x0 = (16 * Math.pow(Math.sin(t), 3)) / 17;const y0 =(13 * Math.cos(t) -5 * Math.cos(2 * t) -2 * Math.cos(3 * t) -Math.cos(4 * t)) /17;return [center + radius * x0, center - radius * y0];});
}// 转换为 path 字符串
function toPath(pointsArr) {return ("M" +pointsArr.map(([x, y]) => `${x.toFixed(2)},${y.toFixed(2)}`).join(" L ") +" Z");
}// 渐变色组
const gradients = [// 圆:蓝紫渐变[{ offset: "0%", color: "#6EE7F9" },{ offset: "50%", color: "#A7F3D0" },{ offset: "100%", color: "#818CF8" },],// 心形:粉橙渐变[{ offset: "0%", color: "#FDE68A" },{ offset: "50%", color: "#FCA5A5" },{ offset: "100%", color: "#F472B6" },],
];const shapes = [toPath(getCircle()), toPath(getHeart())];export default function ShapeMorphHeartDemo() {const shapeRef = useRef(null);const [gradientIndex, setGradientIndex] = useState(0);const current = useRef(0);useEffect(() => {let running = true;const morph = () => {if (!running) return;const from = shapes[current.current % shapes.length];const to = shapes[(current.current + 1) % shapes.length];// 动态切换渐变色setGradientIndex((current.current + 1) % gradients.length);animate(shapeRef.current, {d: [from, to],duration: 1800,ease: "outElastic(1, .7)",complete: () => {current.current = (current.current + 1) % shapes.length;setTimeout(morph, 900);},});};morph();return () => {running = false;};}, []);// 当前渐变色const stops = gradients[gradientIndex];return (<div className="flex flex-col items-center justify-center min-h-[60vh]"><svg width="220" height="220" viewBox="0 0 200 200"><defs><linearGradientid="morphGradient"x1="0%"y1="0%"x2="100%"y2="100%">{stops.map((stop, i) => (<stopkey={i}offset={stop.offset}stopColor={stop.color}stopOpacity="1"/>))}</linearGradient></defs><pathref={shapeRef}d={shapes[0]}fill="url(#morphGradient)"stroke="#2226"strokeWidth="5"style={{filter: "drop-shadow(0 4px 24px #818cf855)",transition: "filter 0.3s",}}/></svg><div className="mt-6 text-lg text-gray-700 font-semibold">圆 ↔ 心形</div></div>);
}
文字动效
import { useEffect, useRef } from "react";
import { animate, stagger } from "animejs";const text = "ifrontend.net".split("");export default function SVGTextAnim() {const letterRefs = useRef([]);useEffect(() => {// 依次弹跳出现animate(letterRefs.current, {translateY: [40, 0],scale: [0.5, 1.1, 1],opacity: [0, 1],fill: ["#818CF8","#F472B6","#FBBF24","#34D399","#60A5FA","#F472B6","#FBBF24","#34D399","#60A5FA","#F472B6","#FBBF24","#34D399",],duration: 1200,delay: stagger(120),ease: "outElastic(1, .7)",});}, []);return (<div className="flex flex-col items-center justify-center min-h-[60vh]"><svgwidth="380"height="100"viewBox="0 0 380 100"style={{ display: "block" }}><defs><linearGradient id="textGradient" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" stopColor="#818CF8" /><stop offset="50%" stopColor="#F472B6" /><stop offset="100%" stopColor="#FBBF24" /></linearGradient></defs>{text.map((char, i) => (<textkey={i}ref={(el) => (letterRefs.current[i] = el)}x={24 + i * 28} // 步进从40改为28,起始点24y={68} // y略微上移fontSize="38" // 字体略小fontFamily="Fira Mono, Menlo, monospace"fontWeight="bold"fill="url(#textGradient)"stroke="#2226"strokeWidth="1.2"opacity="0"style={{filter: "drop-shadow(0 2px 8px #818cf855)",transition: "filter 0.3s",cursor: "default",userSelect: "none",}}>{char}</text>))}</svg><div className="mt-6 text-lg text-gray-700">文字动效</div></div>);
}
说明
- 通过
getTotalLength()
获取 SVG 路径的总长度。 - 设置
strokeDasharray
和strokeDashoffset
实现路径描边动画。 - 使用 animejs 的
animate
方法让路径从无到有地描绘出来。
你还可以为 SVG 的 fill
、stroke
、transform
等属性添加动画,打造更丰富的 SVG 动效。
原文链接:Anime.js超级炫酷的网页动画库之SVG路径动画 - 高质量源码分享平台-免费下载各类网站源码与模板及前沿技术分享,转载请注明出处。