当前位置: 首页 > ai >正文

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 的 fillstroketransform 等属性添加动画,打造更丰富的 SVG 动效。

 原文链接:Anime.js超级炫酷的网页动画库之SVG路径动画 - 高质量源码分享平台-免费下载各类网站源码与模板及前沿技术分享,转载请注明出处。

http://www.xdnf.cn/news/15637.html

相关文章:

  • 信息检索革命:Perplexica+cpolar打造你的专属智能搜索中枢
  • GI6E 加密GRID電碼通信SHELLCODE載入
  • 论文review SfM MVS VGGT: Visual Geometry Grounded Transformer
  • 需要保存至服务器的:常见编辑、发布文章页面基础技巧
  • 配置本地git到gitlab并推送
  • elasticsearch+logstash+kibana+filebeat实现niginx日志收集(未过滤日志内容)
  • .QOI: Lossless Image Compression in O(n) Time
  • Flutter 应用如何设计通知服务
  • Nature Communications:人工有机传入神经为智能机器人提供闭环触觉反馈
  • 半小时部署本地deepseek【1】
  • Hadoop与云原生集成:弹性扩缩容与OSS存储分离架构深度解析
  • Django母婴商城项目实践(五)
  • Linux中的LVS集群技术
  • 二进制写入与文本写入的本质区别:系统视角下的文件操作
  • IT 和OT指的什么?
  • LangChain 源码剖析(七)RunnableBindingBase 深度剖析:给 Runnable“穿衣服“ 的装饰器架构
  • 基于现代R语言【Tidyverse、Tidymodel】的机器学习方法
  • KuiperInfer第八课-实现resnet推理
  • 在ComfyUI中CLIP Text Encode (Prompt)和CLIPTextEncodeFlux的区别
  • git是啥
  • Selenium自动化浏览器操作指南
  • 5 种可行的方法:如何将 Redmi 联系人备份到 Mac
  • 智能Agent场景实战指南 Day 16:Agent记忆系统设计
  • 微流控工程普鲁士蓝水凝胶微球用于增强骨关节炎抗氧化效应
  • PyTorch新手实操 安装
  • 如何区别HTML和HTML5?
  • 【移动端知识】移动端多 WebView 互访方案:Android、iOS 与鸿蒙实现
  • 格式转换Total Excel Converter:20 种格式XLS XLSX 批量转 PDFWord
  • SpringMVC + Tomcat10
  • 链路聚合技术