大家好,我是jobleap.cn的小九。
你想要学习 Anime.js 库的常用用法,并获取一份基于 Next.js 15 的实战教程,要求串联 Anime.js 的核心 API 并完整落地。需要先说明:Anime.js 是前端浏览器端的动画库(非 Node.js 服务端库),Next.js 15 中需在客户端组件中使用它,下面的教程会完整覆盖 Anime.js 所有高频 API,并基于 Next.js 15 的最新特性实现实战案例。
一、环境准备
1. 创建 Next.js 15 项目
# 初始化 Next.js 15 项目npx create-next-app@latest animejs-next15-democdanimejs-next15-demo# 安装 Anime.jsnpminstallanimejs# 可选:安装 @types/animejs 获得类型提示(TypeScript 项目)npminstall-D @types/animejs2. 核心前提
Next.js 15 默认开启 React Server Components (RSC),Anime.js 依赖浏览器 DOM,因此必须在客户端组件中使用(添加'use client'指令)。
二、Anime.js 核心常用 API 梳理
Anime.js 的核心能力围绕「动画目标」「动画属性」「时间控制」「动画编排」「交互控制」展开,常用 API 分类如下:
| 类别 | 核心 API/配置 | 作用 |
|---|---|---|
| 基础配置 | targetsdurationeasing | 指定动画目标、时长、缓动 |
| 时间控制 | delayloopdirection | 延迟、循环、播放方向 |
| 动画属性 | translatescaleopacityrotate | 位移、缩放、透明度、旋转 |
| 动画编排 | anime.timeline() | 时间线(串联/并行动画) |
| 交互控制 | play()pause()restart()seek() | 播放/暂停/重置/跳转 |
| 高级动画 | pathstrokeDashoffset | 路径动画、SVG 描边动画 |
| 回调函数 | completeupdate | 动画完成/更新时触发 |
三、Next.js 15 实战:串联所有常用 API
下面创建一个客户端组件AnimeDemo.tsx,整合 Anime.js 所有高频 API,实现「基础动画 + 时间线 + 路径动画 + 滚动触发 + 交互控制 + SVG 动画」的完整案例。
完整代码(app/anime-demo/page.tsx)
'use client'; // 必须声明为客户端组件 import { useEffect, useRef, useState } from 'react'; import anime from 'animejs/lib/anime.es.js'; // 导入 Anime.js 核心 export default function AnimeJsDemo() { // 1. 定义 DOM 引用(用于指定动画目标) const boxRef = useRef<HTMLDivElement>(null); const svgRef = useRef<SVGSVGElement>(null); const pathRef = useRef<SVGPathElement>(null); const ballRef = useRef<HTMLDivElement>(null); const [isScrollTriggered, setIsScrollTriggered] = useState(false); const animationRef = useRef<anime.AnimeInstance | null>(null); // 保存动画实例用于控制 // 2. 初始化基础动画 + 时间线 useEffect(() => { // 校验 DOM 元素是否存在 if (!boxRef.current || !svgRef.current || !pathRef.current || !ballRef.current) return; // ========== API 1: 基础动画配置(targets/duration/easing/delay/loop/direction) ========== const baseAnimation = anime({ targets: boxRef.current, // 动画目标:指定 DOM 元素 translateX: [0, 300], // 位移:从 0 到 300px scale: [1, 1.5], // 缩放:从 1 到 1.5 倍 opacity: [0.5, 1], // 透明度:从 0.5 到 1 rotate: [0, 360], // 旋转:从 0 到 360 度 duration: 2000, // 动画时长:2000ms(2 秒) easing: 'easeInOutCubic',// 缓动函数:先慢后快再慢 delay: 500, // 延迟 500ms 执行 loop: 2, // 循环 2 次(默认无限循环用 true) direction: 'alternate', // 播放方向:往返(normal=正向,reverse=反向) update: (anim) => { // 回调:动画更新时触发 console.log('基础动画进度:', anim.progress + '%'); }, complete: () => { // 回调:动画完成时触发 console.log('基础动画执行完毕'); }, }); // ========== API 2: 时间线(timeline)—— 串联/并行动画 ========== const timeline = anime.timeline({ easing: 'easeOutExpo', duration: 1500, delay: 100, // 时间线整体延迟 }); // 步骤 1:SVG 描边动画(strokeDashoffset) timeline.add({ targets: svgRef.current.querySelector('path'), strokeDashoffset: [anime.setDashoffset, 0], // 从完整描边隐藏到显示 duration: 2000, label: 'svg-stroke', // 给动画步骤加标签,方便控制 }) // 步骤 2:并行动画(和上一步间隔 0ms,即同时执行) .add({ targets: boxRef.current, backgroundColor: ['#6366f1', '#ec4899'], // 颜色过渡 duration: 1000, }, 0) // 0 表示和上一步同时开始(正值=延迟,负值=提前) // 步骤 3:顺序动画(上一步完成后执行) .add({ targets: boxRef.current, borderRadius: ['0px', '50%'], // 圆角过渡 }); // ========== API 3: 路径动画(沿 SVG 路径运动) ========== const pathAnimation = anime({ targets: ballRef.current, translateX: anime.path(pathRef.current).x, // 沿路径的 X 坐标 translateY: anime.path(pathRef.current).y, // 沿路径的 Y 坐标 rotate: anime.path(pathRef.current).angle, // 沿路径角度旋转 duration: 4000, loop: true, easing: 'linear', autoplay: false, // 初始暂停,后续通过按钮触发 }); // 保存动画实例,用于后续交互控制 animationRef.current = { base: baseAnimation, timeline: timeline, path: pathAnimation, }; // 清理函数:组件卸载时停止所有动画 return () => { baseAnimation.pause(); timeline.pause(); pathAnimation.pause(); }; }, []); // ========== API 4: 滚动触发动画 ========== useEffect(() => { const handleScroll = () => { const scrollTop = window.scrollY; // 滚动到 200px 时触发动画 if (scrollTop > 200 && !isScrollTriggered) { setIsScrollTriggered(true); anime({ targets: '.scroll-trigger', opacity: [0, 1], translateY: [50, 0], duration: 1000, stagger: 200, // 逐个元素延迟(错开动画) }); } }; window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, [isScrollTriggered]); // ========== API 5: 动画交互控制(play/pause/restart/seek) ========== const controlAnimation = (action: 'play' | 'pause' | 'restart' | 'seek') => { if (!animationRef.current?.path) return; switch (action) { case 'play': animationRef.current.path.play(); break; case 'pause': animationRef.current.path.pause(); break; case 'restart': animationRef.current.path.restart(); break; case 'seek': animationRef.current.path.seek(1000); // 跳转到 1000ms 位置 break; } }; return ( <div style={{ padding: '50px', maxWidth: '1200px', margin: '0 auto' }}> <h1>Anime.js + Next.js 15 实战演示</h1> {/* 1. 基础动画演示区 */} <div style={{ margin: '50px 0' }}> <h2>基础动画(位移/缩放/旋转/透明度)</h2> <div ref={boxRef} style={{ width: '100px', height: '100px', backgroundColor: '#6366f1', margin: '20px 0', }} /> </div> {/* 2. SVG 描边 + 路径动画演示区 */} <div style={{ margin: '50px 0' }}> <h2>SVG 描边 + 路径动画</h2> <svg ref={svgRef} width="400" height="200" viewBox="0 0 400 200" style={{ border: '1px solid #eee' }} > <path ref={pathRef} d="M50,100 C150,50 250,150 350,100" fill="none" stroke="#ec4899" strokeWidth="2" strokeDasharray="1000" strokeDashoffset="1000" /> </svg> <div ref={ballRef} style={{ width: '20px', height: '20px', borderRadius: '50%', backgroundColor: '#8b5cf6', position: 'absolute', top: '50%', left: '0', transform: 'translate(-50%, -50%)', }} /> {/* 动画控制按钮 */} <div style={{ marginTop: '20px' }}> <button onClick={() => controlAnimation('play')} style={{ margin: '0 5px' }}> 播放路径动画 </button> <button onClick={() => controlAnimation('pause')} style={{ margin: '0 5px' }}> 暂停路径动画 </button> <button onClick={() => controlAnimation('restart')} style={{ margin: '0 5px' }}> 重置路径动画 </button> <button onClick={() => controlAnimation('seek')} style={{ margin: '0 5px' }}> 跳转到 1000ms 位置 </button> </div> </div> {/* 3. 滚动触发动画演示区 */} <div style={{ height: '800px', margin: '50px 0' }}> <h2 style={{ marginTop: '300px' }}>滚动触发动画(向下滚动查看)</h2> <div className="scroll-trigger" style={{ margin: '10px 0', opacity: 0 }}> 滚动触发元素 1 </div> <div className="scroll-trigger" style={{ margin: '10px 0', opacity: 0 }}> 滚动触发元素 2 </div> <div className="scroll-trigger" style={{ margin: '10px 0', opacity: 0 }}> 滚动触发元素 3 </div> </div> </div> ); }代码关键 API 解释
targets:动画的核心目标,可以是 DOM 元素、选择器、DOM 引用或数组,示例中用boxRef.current指定具体 DOM。- 基础动画属性:
translateX(水平位移)、scale(缩放)、opacity(透明度)、rotate(旋转)是最常用的动画属性,支持「起始值-结束值」数组格式。 - 时间配置:
duration(动画时长)、delay(延迟执行)、loop(循环次数)、direction(播放方向)控制动画的时间行为。 anime.timeline():时间线是 Anime.js 编排复杂动画的核心,通过add()方法串联/并行动画,第二个参数控制执行时机(0=并行,正值=延迟)。- 路径动画:
anime.path(pathRef.current).x/y/angle让元素沿 SVG 路径运动,自动计算坐标和角度。 - 交互控制:通过保存
AnimeInstance实例,调用play()/pause()/restart()/seek()实现动画的手动控制。 - 滚动触发:结合
window.scroll事件和状态判断,实现滚动到指定位置时触发动画,stagger实现元素逐个动画。 - SVG 描边动画:利用
strokeDashoffset和anime.setDashoffset实现描边逐步显示的效果。
四、运行与验证
- 启动 Next.js 项目:
npmrun dev- 访问
http://localhost:3000/anime-demo,可以看到:- 基础动画:方块自动执行位移、缩放、旋转、透明度变化;
- SVG 区域:描边动画自动执行,点击按钮可控制小球沿路径运动;
- 滚动区域:向下滚动到指定位置,元素逐个显示(滚动触发动画)。
五、进阶技巧
- 缓动函数:Anime.js 内置多种缓动函数(如
easeInOutCubic、easeOutExpo、linear),可在 Anime.js 官网 查看所有缓动效果。 - 响应式动画:结合 Next.js 的
useMediaQuery适配不同屏幕尺寸的动画参数。 - 性能优化:动画优先使用
transform和opacity(浏览器硬件加速),避免修改width/height等触发重排的属性。 - 自定义属性:支持对 CSS 自定义属性(
--custom-color)做动画,实现更灵活的样式控制。
总结
- Anime.js 核心是「目标 + 属性 + 时间」,Next.js 15 中需在客户端组件(
'use client')中使用,避免服务端渲染报错; - 常用 API 分为基础配置(
targets/duration)、时间线(timeline)、交互控制(play/pause)、高级动画(路径/SVG)四大类; - 实战中需保存动画实例用于交互控制,结合浏览器事件(如滚动)可实现更贴合业务的动画效果,优先使用
transform/opacity保证性能。