Loading...
Loading...
Compare original and translation side by side
Lightweight, modular, high-performance JavaScript animation engine. Current version: 4.0.0 | Official docs: https://animejs.com/documentation
轻量级、模块化、高性能的JavaScript动画引擎。 当前版本:4.0.0 | 官方文档:https://animejs.com/documentation
| Need | Use |
|---|---|
| Simple one-shot animation | |
| Timers and time control | |
| Orchestrate multiple animations | |
| Real-time updates (mouse, scroll) | |
| Drag-and-drop with physics | |
| Layout changes (FLIP technique) | |
| Responsive animations | |
| Scroll-triggered animations | |
| SVG morphing | |
| SVG line drawing | |
| SVG path following | |
| Text character/word animation | |
| Text scramble effect | |
| Staggered animations | |
| Physics springs | |
| High-performance transforms | |
| Global engine configuration | |
| 需求 | 使用方法 |
|---|---|
| 简单单次动画 | |
| 计时器与时间控制 | |
| 编排多个动画 | |
| 实时更新(鼠标、滚动) | |
| 带物理效果的拖拽 | |
| 布局变化(FLIP技术) | |
| 响应式动画 | |
| 滚动触发动画 | |
| SVG变形 | |
| SVG描边动画 | |
| SVG路径跟随 | |
| 文本字符/单词动画 | |
| 文本打乱效果 | |
| 交错动画 | |
| 物理弹簧效果 | |
| 高性能变换 | |
| 全局引擎配置 | |
createTimeline()revert()cancel()transformopacitywidthheightcreateTimeline()revert()cancel()transformopacitywidthheightnpm install animejs// ES Modules (bundler: Vite, esbuild, etc.)
import { animate, createTimeline, stagger } from 'animejs';
// CommonJS
const { animate } = require('animejs');
// CDN — ES Module
import { animate } from 'https://esm.sh/animejs';
// or JsDelivr
import { animate } from 'https://cdn.jsdelivr.net/npm/animejs/+esm';
// CDN — UMD (script tag)
// <script src="https://cdn.jsdelivr.net/npm/animejs/dist/bundles/anime.umd.min.js"></script>
// const { animate } = anime;npm install animejs// ES Modules(打包工具:Vite、esbuild等)
import { animate, createTimeline, stagger } from 'animejs';
// CommonJS
const { animate } = require('animejs');
// CDN — ES Module
import { animate } from 'https://esm.sh/animejs';
// 或JsDelivr
import { animate } from 'https://cdn.jsdelivr.net/npm/animejs/+esm';
// CDN — UMD(script标签)
// <script src="https://cdn.jsdelivr.net/npm/animejs/dist/bundles/anime.umd.min.js"></script>
// const { animate } = anime;| File | Type |
|---|---|
| ES modules entry point |
| CommonJS entry point |
| Minified ES bundle |
| Minified UMD bundle |
| 文件 | 类型 |
|---|---|
| ES模块入口 |
| CommonJS入口 |
| 压缩后的ES包 |
| 压缩后的UMD包 |
| Module | Size |
|---|---|
| Timer | 5.60 KB |
| Animation | +5.20 KB |
| Timeline | +0.55 KB |
| Animatable | +0.40 KB |
| Draggable | +6.41 KB |
| Scroll | +4.30 KB |
| Scope | +0.22 KB |
| SVG | 0.35 KB |
| Stagger | +0.48 KB |
| Spring | 0.52 KB |
| WAAPI | 3.50 KB |
| Total | ~24.50 KB |
| 模块 | 大小 |
|---|---|
| Timer | 5.60 KB |
| Animation | +5.20 KB |
| Timeline | +0.55 KB |
| Animatable | +0.40 KB |
| Draggable | +6.41 KB |
| Scroll | +4.30 KB |
| Scope | +0.22 KB |
| SVG | 0.35 KB |
| Stagger | +0.48 KB |
| Spring | 0.52 KB |
| WAAPI | 3.50 KB |
| 总计 | ~24.50 KB |
import {
animate, // Main animation function
createTimer, // Timer without animated properties
createTimeline, // Animation sequencer
createAnimatable, // Real-time animatable properties
createDraggable, // Draggable elements
createScope, // Responsive scope
createLayout, // Automatic layout animations
onScroll, // Scroll Observer
stagger, // Staggering utility
createSpring, // Physics spring
waapi, // Enhanced Web Animation API
utils, // Math and DOM utilities
// SVG
morphTo,
createDrawable,
createMotionPath,
// Text
splitText,
scrambleText,
// Engine
engine,
} from 'animejs';import {
animate, // 主动画函数
createTimer, // 无动画属性的计时器
createTimeline, // 动画序列编排器
createAnimatable, // 实时可动画属性
createDraggable, // 可拖拽元素
createScope, // 响应式作用域
createLayout, // 自动布局动画
onScroll, // 滚动观察者
stagger, // 交错动画工具
createSpring, // 物理弹簧效果
waapi, // 增强版Web动画API
utils, // 数学与DOM工具
// SVG相关
morphTo,
createDrawable,
createMotionPath,
// 文本相关
splitText,
scrambleText,
// 引擎
engine,
} from 'animejs';animate(targets, parameters);animate(targets, parameters);// CSS Selector
animate('.box', { x: 100 });
// DOM Element
animate(document.querySelector('.box'), { x: 100 });
// NodeList / Array of elements
animate(document.querySelectorAll('.box'), { x: 100 });
// JavaScript Object
const obj = { value: 0 };
animate(obj, { value: 100, onUpdate: () => console.log(obj.value) });
// Mixed array
animate(['.box', myElement, myObject], { opacity: 0 });// CSS选择器
animate('.box', { x: 100 });
// DOM元素
animate(document.querySelector('.box'), { x: 100 });
// NodeList / 元素数组
animate(document.querySelectorAll('.box'), { x: 100 });
// JavaScript对象
const obj = { value: 0 };
animate(obj, { value: 100, onUpdate: () => console.log(obj.value) });
// 混合数组
animate(['.box', myElement, myObject], { opacity: 0 });// CSS Properties
animate('.el', {
width: '200px',
backgroundColor: '#ff0000',
opacity: 0.5,
borderRadius: '50%',
});
// CSS Transforms (individual, no conflicts)
animate('.el', {
x: 100, // translateX
y: 50, // translateY
z: 0, // translateZ
rotate: 90, // rotateZ (degrees by default)
rotateX: 45,
rotateY: 45,
scale: 1.5,
scaleX: 2,
scaleY: 0.5,
skew: 15,
skewX: 10,
skewY: 10,
});
// CSS Variables
animate('.el', { '--my-color': '#ff0000' });
// HTML Attributes
animate('input[type=range]', { value: 50 });
// SVG Attributes
animate('circle', { r: 50, cx: 100, cy: 100 });
// JS Object properties
const data = { count: 0 };
animate(data, { count: 100 });// CSS属性
animate('.el', {
width: '200px',
backgroundColor: '#ff0000',
opacity: 0.5,
borderRadius: '50%',
});
// CSS变换(独立设置,无冲突)
animate('.el', {
x: 100, // translateX
y: 50, // translateY
z: 0, // translateZ
rotate: 90, // rotateZ(默认单位为度)
rotateX: 45,
rotateY: 45,
scale: 1.5,
scaleX: 2,
scaleY: 0.5,
skew: 15,
skewX: 10,
skewY: 10,
});
// CSS变量
animate('.el', { '--my-color': '#ff0000' });
// HTML属性
animate('input[type=range]', { value: 50 });
// SVG属性
animate('circle', { r: 50, cx: 100, cy: 100 });
// JS对象属性
const data = { count: 0 };
animate(data, { count: 100 });// Numerical
animate('.el', { x: 100 });
// With unit (automatic conversion)
animate('.el', { width: '50%' }); // converts from px
animate('.el', { x: '10rem' });
// Relative (JS only)
animate('.el', { x: '+=50' }); // add 50
animate('.el', { x: '-=50' }); // subtract 50
animate('.el', { x: '*=2' }); // multiply by 2
// Color
animate('.el', { backgroundColor: 'rgb(255, 0, 0)' });
animate('.el', { backgroundColor: '#ff0000' });
animate('.el', { backgroundColor: 'hsl(0, 100%, 50%)' });
// Color function (WAAPI)
animate('.el', { color: 'oklch(70% 0.2 120)' });
// CSS variable as value
animate('.el', { x: 'var(--offset)' });
// Function-based (per element)
animate('.el', {
x: (el, index, total) => index * 50,
delay: (el, index) => index * 100,
});// 数值
animate('.el', { x: 100 });
// 带单位(自动转换)
animate('.el', { width: '50%' }); // 从px转换
animate('.el', { x: '10rem' });
// 相对值(仅JS)
animate('.el', { x: '+=50' }); // 增加50
animate('.el', { x: '-=50' }); // 减少50
animate('.el', { x: '*=2' }); // 乘以2
// 颜色
animate('.el', { backgroundColor: 'rgb(255, 0, 0)' });
animate('.el', { backgroundColor: '#ff0000' });
animate('.el', { backgroundColor: 'hsl(0, 100%, 50%)' });
// 颜色函数(WAAPI)
animate('.el', { color: 'oklch(70% 0.2 120)' });
// CSS变量作为值
animate('.el', { x: 'var(--offset)' });
// 基于函数的取值(按元素)
animate('.el', {
x: (el, index, total) => index * 50,
delay: (el, index) => index * 100,
});animate('.el', {
x: {
to: 200,
from: 0, // forced initial value
delay: 200,
duration: 800,
ease: 'inOutExpo',
composition: 'add', // 'replace' | 'add' | 'blend'
modifier: v => Math.round(v),
},
});animate('.el', {
x: {
to: 200,
from: 0, // 强制初始值
delay: 200,
duration: 800,
ease: 'inOutExpo',
composition: 'add', // 'replace' | 'add' | 'blend'
modifier: v => Math.round(v),
},
});// Tween values keyframes (array of values)
animate('.el', {
x: [0, 50, 100, 50, 0],
});
// Tween parameters keyframes
animate('.el', {
x: [
{ to: 100, duration: 500, ease: 'outExpo' },
{ to: 0, duration: 500, ease: 'inExpo' },
],
});
// Duration-based keyframes (JS only)
animate('.el', {
keyframes: [
{ x: 100, duration: 400 },
{ y: 50, duration: 300 },
{ rotate: 90, duration: 500 },
],
});
// Percentage-based keyframes (JS only)
animate('.el', {
keyframes: {
'0%': { x: 0, opacity: 1 },
'50%': { x: 100, opacity: 0.5 },
'100%': { x: 200, opacity: 1 },
},
});// 补间值关键帧(值数组)
animate('.el', {
x: [0, 50, 100, 50, 0],
});
// 补间参数关键帧
animate('.el', {
x: [
{ to: 100, duration: 500, ease: 'outExpo' },
{ to: 0, duration: 500, ease: 'inExpo' },
],
});
// 基于时长的关键帧(仅JS)
animate('.el', {
keyframes: [
{ x: 100, duration: 400 },
{ y: 50, duration: 300 },
{ rotate: 90, duration: 500 },
],
});
// 基于百分比的关键帧(仅JS)
animate('.el', {
keyframes: {
'0%': { x: 0, opacity: 1 },
'50%': { x: 100, opacity: 0.5 },
'100%': { x: 200, opacity: 1 },
},
});animate('.el', {
x: 100,
delay: 500, // delay before starting (ms)
duration: 1000, // duration (ms)
loop: true, // true = infinite, number = repetitions
loopDelay: 200, // pause between loops (JS only)
alternate: true, // reverses direction on each loop
reversed: false, // plays in reverse
autoplay: true, // starts automatically
frameRate: 60, // max FPS (JS only)
playbackRate: 1, // speed (0.5 = half speed)
playbackEase: 'linear', // global easing for the animation (JS only)
persist: false, // keeps styles after completion (WAAPI only)
});animate('.el', {
x: 100,
delay: 500, // 开始前延迟(毫秒)
duration: 1000, // 时长(毫秒)
loop: true, // true=无限循环,数字=重复次数
loopDelay: 200, // 循环间隔(仅JS)
alternate: true, // 每次循环反向播放
reversed: false, // 反向播放
autoplay: true, // 自动开始
frameRate: 60, // 最大帧率(仅JS)
playbackRate: 1, // 播放速度(0.5=半速)
playbackEase: 'linear', // 动画全局缓动(仅JS)
persist: false, // 完成后保留样式(仅WAAPI)
});animate('.el', {
x: 100,
onBegin: (anim) => console.log('started'), // JS only
onComplete: (anim) => console.log('complete'),
onBeforeUpdate: (anim) => {}, // JS only
onUpdate: (anim) => console.log(anim.progress), // JS only
onRender: (anim) => {}, // JS only
onLoop: (anim) => {}, // JS only
onPause: (anim) => {}, // JS only
}).then((anim) => console.log('promise resolved'));animate('.el', {
x: 100,
onBegin: (anim) => console.log('已启动'), // 仅JS
onComplete: (anim) => console.log('已完成'),
onBeforeUpdate: (anim) => {}, // 仅JS
onUpdate: (anim) => console.log(anim.progress), // 仅JS
onRender: (anim) => {}, // 仅JS
onLoop: (anim) => {}, // 仅JS
onPause: (anim) => {}, // 仅JS
}).then((anim) => console.log('Promise已解决'));const anim = animate('.el', { x: 100, autoplay: false });
anim.play(); // play
anim.pause(); // pause
anim.resume(); // resume
anim.reverse(); // reverse direction
anim.restart(); // restart from the beginning
anim.alternate(); // alternate direction
anim.complete(); // jump to end
anim.cancel(); // cancel without reverting
anim.revert(); // cancel and restore original values
anim.reset(); // reset to initial state (JS only)
anim.seek(500); // jump to time in ms
anim.stretch(2000); // stretch total duration (JS only)
anim.refresh(); // recompute values (JS only)const anim = animate('.el', { x: 100, autoplay: false });
anim.play(); // 播放
anim.pause(); // 暂停
anim.resume(); // 恢复
anim.reverse(); // 反向
anim.restart(); // 重启
anim.alternate(); // 切换方向
anim.complete(); // 跳至结束
anim.cancel(); // 取消且不还原
anim.revert(); // 取消并还原初始值
anim.reset(); // 重置为初始状态(仅JS)
anim.seek(500); // 跳至指定时间(毫秒)
anim.stretch(2000); // 拉伸总时长(仅JS)
anim.refresh(); // 重新计算值(仅JS)anim.duration // total duration (ms)
anim.currentTime // current time (ms)
anim.progress // progress 0-1
anim.paused // boolean
anim.began // boolean
anim.completed // boolean
anim.reversed // boolean
anim.targets // array of targetsanim.duration // 总时长(毫秒)
anim.currentTime // 当前时间(毫秒)
anim.progress // 进度0-1
anim.paused // 布尔值
anim.began // 布尔值
anim.completed // 布尔值
anim.reversed // 布尔值
anim.targets // 目标元素数组import { createTimer } from 'animejs';
const timer = createTimer({
duration: 2000,
loop: true,
onUpdate: (t) => console.log(t.currentTime),
onComplete: (t) => console.log('done'),
});animate()import { createTimer } from 'animejs';
const timer = createTimer({
duration: 2000,
loop: true,
onUpdate: (t) => console.log(t.currentTime),
onComplete: (t) => console.log('完成'),
});animate()import { createTimeline } from 'animejs';
const tl = createTimeline({
loop: true,
defaults: { duration: 500, ease: 'outExpo' }, // defaults for all animations
});
// Add animations (chained in sequence by default)
tl.add('.box', { x: 100 })
.add('.circle', { y: 100 })
.add('.text', { opacity: 0 });import { createTimeline } from 'animejs';
const tl = createTimeline({
loop: true,
defaults: { duration: 500, ease: 'outExpo' }, // 所有动画的默认设置
});
// 添加动画(默认按顺序链式执行)
tl.add('.box', { x: 100 })
.add('.circle', { y: 100 })
.add('.text', { opacity: 0 });tl.add('.el', { x: 100 }) // after the previous
.add('.el', { y: 50 }, 500) // absolute: at 500ms from start
.add('.el', { scale: 2 }, '+=200') // relative: 200ms AFTER the previous ends
.add('.el', { rotate: 90 }, '-=100') // relative: 100ms BEFORE the previous ends
.add('.el', { opacity: 0 }, '<') // at the same time as the previous
.add('.el', { opacity: 1 }, '<100') // 100ms after the start of the previous
.label('myLabel') // label at current time
.add('.el', { x: 0 }, 'myLabel'); // position by labeltl.add('.el', { x: 100 }) // 在上一个动画之后
.add('.el', { y: 50 }, 500) // 绝对时间:从开始起500毫秒处
.add('.el', { scale: 2 }, '+=200') // 相对时间:上一个动画结束后200毫秒
.add('.el', { rotate: 90 }, '-=100') // 相对时间:上一个动画结束前100毫秒
.add('.el', { opacity: 0 }, '<') // 与上一个动画同时开始
.add('.el', { opacity: 1 }, '<100') // 上一个动画开始后100毫秒
.label('myLabel') // 在当前时间添加标签
.add('.el', { x: 0 }, 'myLabel'); // 按标签位置添加tl.add(targets, params, position) // add animation
.set(targets, params, position) // set values instantly
.sync(animation, position) // sync external animation
.call(fn, position) // call function at a specific time
.label('name', position) // add label
.remove(targets) // remove animations for targets
.init() // initialize without playing
// Playback (same as animate)
tl.play() .pause() .resume() .reverse()
.restart() .alternate() .complete()
.cancel() .revert() .reset()
.seek(ms) .stretch(ms) .refresh()tl.add(targets, params, position) // 添加动画
.set(targets, params, position) // 立即设置值
.sync(animation, position) // 同步外部动画
.call(fn, position) // 在指定时间调用函数
.label('name', position) // 添加标签
.remove(targets) // 移除目标元素的动画
.init() // 初始化但不播放
// 播放控制(与animate()相同)
tl.play() .pause() .resume() .reverse()
.restart() .alternate() .complete()
.cancel() .revert() .reset()
.seek(ms) .stretch(ms) .refresh()import { createAnimatable } from 'animejs';
const box = createAnimatable('.box', {
x: { duration: 500, ease: 'outSpring' },
y: { duration: 500, ease: 'outSpring' },
scale: { duration: 300 },
// unit: 'px', // default unit
// modifier: v => v, // global modifier
});
// Setter: animates to the new value
box.x(200);
box.y(100);
box.scale(1.5);
// Getter: returns current value
console.log(box.x()); // null if not yet set
// Revert
box.revert();import { createAnimatable } from 'animejs';
const box = createAnimatable('.box', {
x: { duration: 500, ease: 'outSpring' },
y: { duration: 500, ease: 'outSpring' },
scale: { duration: 300 },
// unit: 'px', // 默认单位
// modifier: v => v, // 全局修饰器
});
// 设置器:动画到新值
box.x(200);
box.y(100);
box.scale(1.5);
// 获取器:返回当前值
console.log(box.x()); // 未设置时返回null
// 还原
box.revert();import { createDraggable, createSpring } from 'animejs';
const draggable = createDraggable('.card', {
// Axis constraints
x: true, // allow drag on X
y: false, // lock Y axis
// x: { mapTo: anotherElement }, // map position to another element
// Container and bounds
container: '.wrapper', // selector, element, 'window', or 'parent'
containerPadding: 20, // inner padding of the container
containerFriction: 0.8, // friction when dragged outside the container
// Snap
snap: 50, // number, array, or function
// snap: [0, 100, 200, 300],
// snap: (val) => Math.round(val / 50) * 50,
// Release physics
releaseEase: createSpring({ stiffness: 200, damping: 15 }),
releaseMass: 1,
releaseStiffness: 200,
releaseDamping: 15,
releaseContainerFriction: 0.85,
// Velocity
velocityMultiplier: 1,
minVelocity: 0,
maxVelocity: Infinity,
dragSpeed: 1,
dragThreshold: 0, // min pixels to start dragging
// Auto-scroll
scrollThreshold: 20,
scrollSpeed: 10,
// Cursor
cursor: 'grab', // CSS cursor on hover
trigger: '.handle', // element that triggers the drag
// Callbacks
onGrab: (d) => {},
onDrag: (d) => {},
onUpdate: (d) => {},
onRelease: (d) => {},
onSnap: (d) => {},
onSettle: (d) => {},
onResize: (d) => {},
onAfterResize: (d) => {},
});
// Methods
draggable.enable();
draggable.disable();
draggable.setX(100);
draggable.setY(50);
draggable.animateInView();
draggable.scrollInView();
draggable.stop();
draggable.reset();
draggable.revert();
draggable.refresh();import { createDraggable, createSpring } from 'animejs';
const draggable = createDraggable('.card', {
// 轴约束
x: true, // 允许X轴拖拽
y: false, // 锁定Y轴
// x: { mapTo: anotherElement }, // 将位置映射到另一个元素
// 容器与边界
container: '.wrapper', // 选择器、元素、'window'或'parent'
containerPadding: 20, // 容器内边距
containerFriction: 0.8, // 拖拽出容器时的摩擦力
// 吸附
snap: 50, // 数字、数组或函数
// snap: [0, 100, 200, 300],
// snap: (val) => Math.round(val / 50) * 50,
// 释放物理效果
releaseEase: createSpring({ stiffness: 200, damping: 15 }),
releaseMass: 1,
releaseStiffness: 200,
releaseDamping: 15,
releaseContainerFriction: 0.85,
// 速度
velocityMultiplier: 1,
minVelocity: 0,
maxVelocity: Infinity,
dragSpeed: 1,
dragThreshold: 0, // 触发拖拽的最小像素
// 自动滚动
scrollThreshold: 20,
scrollSpeed: 10,
// 光标
cursor: 'grab', // hover时的CSS光标
trigger: '.handle', // 触发拖拽的元素
// 回调函数
onGrab: (d) => {},
onDrag: (d) => {},
onUpdate: (d) => {},
onRelease: (d) => {},
onSnap: (d) => {},
onSettle: (d) => {},
onResize: (d) => {},
onAfterResize: (d) => {},
});
// 方法
draggable.enable();
draggable.disable();
draggable.setX(100);
draggable.setY(50);
draggable.animateInView();
draggable.scrollInView();
draggable.stop();
draggable.reset();
draggable.revert();
draggable.refresh();import { createLayout } from 'animejs';
const layout = createLayout('.container', {
children: true, // animate container children
duration: 600,
ease: 'outExpo',
properties: ['width', 'height', 'transform', 'opacity'],
// Enter/exit states
enterFrom: { opacity: 0, scale: 0.5 },
leaveTo: { opacity: 0, scale: 0.5 },
swapAt: 0.5, // swap point (0-1)
});
// Typical usage
layout.record(); // capture current positions
// ... make DOM changes ...
layout.animate(); // animate from previous position to new one
// Or combined:
layout.update(() => {
// DOM changes here
});
layout.revert(); // revert animationimport { createLayout } from 'animejs';
const layout = createLayout('.container', {
children: true, // 为容器子元素添加动画
duration: 600,
ease: 'outExpo',
properties: ['width', 'height', 'transform', 'opacity'],
// 进入/退出状态
enterFrom: { opacity: 0, scale: 0.5 },
leaveTo: { opacity: 0, scale: 0.5 },
swapAt: 0.5, // 交换点(0-1)
});
// 典型用法
layout.record(); // 记录当前位置
// ... 进行DOM变更 ...
layout.animate(); // 从之前的位置动画到新位置
// 或合并使用:
layout.update(() => {
// 此处进行DOM变更
});
layout.revert(); // 还原动画<!-- Elements with the same layout-id are tracked across containers -->
<div data-layout-id="card-1" class="container-a">Card</div>
<!-- After moving to the other container: -->
<div data-layout-id="card-1" class="container-b">Card</div><!-- 拥有相同layout-id的元素会在容器间被追踪 -->
<div data-layout-id="card-1" class="container-a">卡片</div>
<!-- 移动到另一个容器后: -->
<div data-layout-id="card-1" class="container-b">卡片</div>// CSS display property animation
// DOM reorder animation
// Enter / Exit animations
// Modal dialog animations
// Swap parent animations (element moves between parent containers)// CSS display属性动画
// DOM重排动画
// 进入/退出动画
// 模态框动画
// 跨父容器动画(元素在父容器间移动)import { createScope } from 'animejs';
const scope = createScope({
root: '.my-component', // root element (selector context)
defaults: { duration: 600, ease: 'outExpo' },
mediaQueries: {
mobile: '(max-width: 768px)',
portrait: '(orientation: portrait)',
dark: '(prefers-color-scheme: dark)',
},
});
// add() re-runs whenever a media query changes
scope.add(({ matches, root }) => {
const isMobile = matches.mobile;
createTimeline()
.add('.box', {
x: isMobile ? 0 : 200,
y: isMobile ? 100 : 0,
});
// Optionally return a cleanup function
return () => {};
});
// addOnce() runs only once (does not re-run on media query change)
scope.addOnce(() => {
animate('.logo', { opacity: 1, delay: 500 });
});
scope.revert(); // cleans up all animations in the scope
scope.refresh(); // re-runs all constructors
scope.keepTime(); // preserves time when refreshingimport { createScope } from 'animejs';
const scope = createScope({
root: '.my-component', // 根元素(选择器上下文)
defaults: { duration: 600, ease: 'outExpo' },
mediaQueries: {
mobile: '(max-width: 768px)',
portrait: '(orientation: portrait)',
dark: '(prefers-color-scheme: dark)',
},
});
// add()会在媒体查询变化时重新执行
scope.add(({ matches, root }) => {
const isMobile = matches.mobile;
createTimeline()
.add('.box', {
x: isMobile ? 0 : 200,
y: isMobile ? 100 : 0,
});
// 可选返回清理函数
return () => {};
});
// addOnce()仅执行一次(媒体查询变化时不重新执行)
scope.addOnce(() => {
animate('.logo', { opacity: 1, delay: 500 });
});
scope.revert(); // 清理作用域内的所有动画
scope.refresh(); // 重新执行所有构造函数
scope.keepTime(); // 刷新时保留时间import { animate, onScroll } from 'animejs';
// As the autoplay value of an animation
animate('.el', {
x: 200,
autoplay: onScroll(),
});
// Full configuration
animate('.section', {
opacity: [0, 1],
autoplay: onScroll({
container: window, // scroll container
target: '.section', // observed element (defaults to animation target)
axis: 'y', // 'x' | 'y'
debug: false, // shows visual markers
// Thresholds: when the element enters/leaves
// Shorthand: 'top bottom' = when top of element hits bottom of viewport
enter: 'bottom top', // enters when scrolling down
leave: 'top bottom', // leaves when scrolling
// Numeric values (0-1 relative to viewport)
enter: 0.5, // at the viewport midpoint
// Relative values
enter: '50% 100%', // 50% of the element at 100% of the container
repeat: true, // repeats the animation each time
// Synchronisation modes
sync: true, // syncs progress with scroll
sync: 'play', // calls play() on enter
sync: 'restart', // calls restart() on enter
sync: 'resume', // calls resume() on enter
// Callbacks
onEnter: (obs) => {},
onEnterForward: (obs) => {},
onEnterBackward: (obs) => {},
onLeave: (obs) => {},
onLeaveForward: (obs) => {},
onLeaveBackward: (obs) => {},
onUpdate: (obs) => {},
onSyncComplete: (obs) => {},
onResize: (obs) => {},
}),
});import { animate, onScroll } from 'animejs';
// 作为动画的autoplay值
animate('.el', {
x: 200,
autoplay: onScroll(),
});
// 完整配置
animate('.section', {
opacity: [0, 1],
autoplay: onScroll({
container: window, // 滚动容器
target: '.section', // 观察元素(默认是动画目标)
axis: 'y', // 'x' | 'y'
debug: false, // 显示视觉标记
// 阈值:元素进入/离开的条件
// 简写:'top bottom' = 元素顶部碰到视口底部时
enter: 'bottom top', // 向下滚动时进入
leave: 'top bottom', // 滚动时离开
// 数值(0-1,相对于视口)
enter: 0.5, // 在视口中点
// 相对值
enter: '50% 100%', // 元素50%进入容器100%位置
repeat: true, // 每次进入都重复动画
// 同步模式
sync: true, // 进度与滚动同步
sync: 'play', // 进入时调用play()
sync: 'restart', // 进入时调用restart()
sync: 'resume', // 进入时调用resume()
// 回调函数
onEnter: (obs) => {},
onEnterForward: (obs) => {},
onEnterBackward: (obs) => {},
onLeave: (obs) => {},
onLeaveForward: (obs) => {},
onLeaveBackward: (obs) => {},
onUpdate: (obs) => {},
onSyncComplete: (obs) => {},
onResize: (obs) => {},
}),
});const obs = onScroll({ target: '.el' });
obs.link(anim); // link an animation
obs.refresh(); // recompute thresholds
obs.revert(); // destroy the observerconst obs = onScroll({ target: '.el' });
obs.link(anim); // 关联动画
obs.refresh(); // 重新计算阈值
obs.revert(); // 销毁观察者import { animate, morphTo, createDrawable, createMotionPath } from 'animejs';
// morphTo — SVG shape morphing
animate('#shape-a', {
d: morphTo('#shape-b'), // morph to another element's path
duration: 1000,
ease: 'inOutQuad',
});
// createDrawable — SVG line drawing animation
const drawable = createDrawable('path');
animate(drawable, {
draw: '0 1', // from start to end of stroke
// draw: ['0 0', '0 1', '1 1'], // keyframes
duration: 1500,
ease: 'inOutSine',
});
// draw: [start, end] where start and end are 0-1
// createMotionPath — Follow an SVG path
animate('.car', {
...createMotionPath('.road'), // spreads x, y, rotate properties
duration: 3000,
ease: 'linear',
});import { animate, morphTo, createDrawable, createMotionPath } from 'animejs';
// morphTo — SVG形状变形
animate('#shape-a', {
d: morphTo('#shape-b'), // 变形为另一个元素的路径
duration: 1000,
ease: 'inOutQuad',
});
// createDrawable — SVG描边动画
const drawable = createDrawable('path');
animate(drawable, {
draw: '0 1', // 从描边起点到终点
// draw: ['0 0', '0 1', '1 1'], // 关键帧
duration: 1500,
ease: 'inOutSine',
});
// draw: [start, end] 其中start和end为0-1
// createMotionPath — 跟随SVG路径
animate('.car', {
...createMotionPath('.road'), // 展开x、y、rotate属性
duration: 3000,
ease: 'linear',
});import { splitText, animate, stagger } from 'animejs';
const splitter = splitText('.heading', {
lines: true,
words: true,
chars: true,
includeSpaces: false,
debug: false,
accessible: true, // aria-hidden on spans, aria-label on parent
});
// Animate characters
animate(splitter.chars, {
opacity: [0, 1],
y: [20, 0],
delay: stagger(30),
duration: 600,
ease: 'outExpo',
});
// Animate words
animate(splitter.words, {
scale: [0.8, 1],
delay: stagger(50),
});
// Available properties
splitter.lines // array of line elements
splitter.words // array of word elements
splitter.chars // array of character elements
// Methods
splitter.addEffect((el) => {
// custom effect logic
});
splitter.refresh(); // recompute after resize
splitter.revert(); // restore original HTMLimport { splitText, animate, stagger } from 'animejs';
const splitter = splitText('.heading', {
lines: true,
words: true,
chars: true,
includeSpaces: false,
debug: false,
accessible: true, // 为span添加aria-hidden,为父元素添加aria-label
});
// 为字符添加动画
animate(splitter.chars, {
opacity: [0, 1],
y: [20, 0],
delay: stagger(30),
duration: 600,
ease: 'outExpo',
});
// 为单词添加动画
animate(splitter.words, {
scale: [0.8, 1],
delay: stagger(50),
});
// 可用属性
splitter.lines // 行元素数组
splitter.words // 单词元素数组
splitter.chars // 字符元素数组
// 方法
splitter.addEffect((el) => {
// 自定义效果逻辑
});
splitter.refresh(); // 调整后重新计算
splitter.revert(); // 恢复原始HTMLsplitText('.el', {
lines: { class: 'my-line', wrap: '.wrapper', clone: false },
words: { class: 'my-word' },
chars: { class: 'my-char' },
});splitText('.el', {
lines: { class: 'my-line', wrap: '.wrapper', clone: false },
words: { class: 'my-word' },
chars: { class: 'my-char' },
});import { animate, scrambleText } from 'animejs';
animate('.heading', {
...scrambleText({
text: 'New text', // destination text
chars: 'abcdefghijklmnopqrstuvwxyz', // scramble character set
override: false, // overwrite current text
ease: 'linear',
cursor: true, // show cursor at the end
revealRate: 0.5,
revealDelay: 0,
settleRate: 0.5,
settleDuration: 1000,
delay: 0,
duration: 1000,
perturbation: 1,
from: 'start', // 'start' | 'end' | 'center' | number
reversed: false,
seed: 0,
onChange: (val, target) => {},
}),
});import { animate, scrambleText } from 'animejs';
animate('.heading', {
...scrambleText({
text: 'New text', // 目标文本
chars: 'abcdefghijklmnopqrstuvwxyz', // 打乱字符集
override: false, // 是否覆盖当前文本
ease: 'linear',
cursor: true, // 在末尾显示光标
revealRate: 0.5,
revealDelay: 0,
settleRate: 0.5,
settleDuration: 1000,
delay: 0,
duration: 1000,
perturbation: 1,
from: 'start', // 'start' | 'end' | 'center' | 数字
reversed: false,
seed: 0,
onChange: (val, target) => {},
}),
});import { animate, stagger } from 'animejs';
// Time staggering (delay per index)
animate('.dots', {
y: -20,
delay: stagger(100), // 0, 100, 200, 300...
delay: stagger(100, { start: 200 }), // 200, 300, 400...
delay: stagger(100, { from: 'center' }), // from the center outward
delay: stagger(100, { from: 2 }), // from index 2
delay: stagger(100, { reversed: true }), // reversed
delay: stagger(100, { ease: 'inOutQuad' }), // with easing
});
// Value staggering (range between first and last element)
animate('.dots', {
scale: stagger([0.5, 1.5]), // from 0.5 to 1.5
x: stagger(['-100px', '100px']),
});
// 2D Grid staggering
animate('.grid-item', {
scale: stagger(0.1, {
grid: [10, 10], // columns x rows
from: 'center', // origin point
axis: 'x', // 'x' | 'y' | undefined (diagonal)
}),
});
// Timeline staggering (time positions)
createTimeline()
.add('.el', { y: -10 }, stagger(50)); // each element offset by +50ms
// Full parameters
stagger(value, {
start: 0, // start value or time
from: 'first', // 'first'|'center'|'last'|'edges'|index|[col,row]
reversed: false,
ease: 'linear',
grid: [cols, rows],
axis: 'x', // 'x'|'y'
modifier: (v) => v,
use: 'delay', // property to stagger
total: undefined, // forced total element count
});import { animate, stagger } from 'animejs';
// 时间交错(按索引延迟)
animate('.dots', {
y: -20,
delay: stagger(100), // 0, 100, 200, 300...
delay: stagger(100, { start: 200 }), // 200, 300, 400...
delay: stagger(100, { from: 'center' }), // 从中心向外
delay: stagger(100, { from: 2 }), // 从索引2开始
delay: stagger(100, { reversed: true }), // 反向
delay: stagger(100, { ease: 'inOutQuad' }), // 带缓动
});
// 值交错(第一个到最后一个元素的范围)
animate('.dots', {
scale: stagger([0.5, 1.5]), // 从0.5到1.5
x: stagger(['-100px', '100px']),
});
// 2D网格交错
animate('.grid-item', {
scale: stagger(0.1, {
grid: [10, 10], // 列数 x 行数
from: 'center', // 起始点
axis: 'x', // 'x' | 'y' | undefined(对角线)
}),
});
// 时间线交错(时间位置)
createTimeline()
.add('.el', { y: -10 }, stagger(50)); // 每个元素偏移+50毫秒
// 完整参数
stagger(value, {
start: 0, // 起始值或时间
from: 'first', // 'first'|'center'|'last'|'edges'|索引|[列,行]
reversed: false,
ease: 'linear',
grid: [cols, rows],
axis: 'x', // 'x'|'y'
modifier: (v) => v,
use: 'delay', // 要交错的属性
total: undefined, // 强制元素总数
});// Syntax: 'type(exponent)'
'linear'
'ease' // CSS alias
// In / Out / InOut — 3 forms:
'in(n)' // inSine ~ in(1.675)
'out(n)'
'inOut(n)'
// Predefined aliases (shortcuts)
'inSine' 'outSine' 'inOutSine'
'inQuad' 'outQuad' 'inOutQuad'
'inCubic' 'outCubic' 'inOutCubic'
'inQuart' 'outQuart' 'inOutQuart'
'inQuint' 'outQuint' 'inOutQuint'
'inExpo' 'outExpo' 'inOutExpo'
'inCirc' 'outCirc' 'inOutCirc'
'inBack' 'outBack' 'inOutBack'
'inBounce' 'outBounce' 'inOutBounce'
'inElastic' 'outElastic' 'inOutElastic'// 语法:'type(exponent)'
'linear'
'ease' // CSS别名
// In / Out / InOut — 三种形式:
'in(n)' // inSine ~ in(1.675)
'out(n)'
'inOut(n)'
// 预定义别名(快捷方式)
'inSine' 'outSine' 'inOutSine'
'inQuad' 'outQuad' 'inOutQuad'
'inCubic' 'outCubic' 'inOutCubic'
'inQuart' 'outQuart' 'inOutQuart'
'inQuint' 'outQuint' 'inOutQuint'
'inExpo' 'outExpo' 'inOutExpo'
'inCirc' 'outCirc' 'inOutCirc'
'inBack' 'outBack' 'inOutBack'
'inBounce' 'outBounce' 'inOutBounce'
'inElastic' 'outElastic' 'inOutElastic'// cubicBezier(x1, y1, x2, y2)
ease: 'cubicBezier(0.25, 0.1, 0.25, 1.0)'
// or using createCubicBezier:
import { createCubicBezier } from 'animejs';
ease: createCubicBezier(0.25, 0.1, 0.25, 1.0)// cubicBezier(x1, y1, x2, y2)
ease: 'cubicBezier(0.25, 0.1, 0.25, 1.0)'
// 或使用createCubicBezier:
import { createCubicBezier } from 'animejs';
ease: createCubicBezier(0.25, 0.1, 0.25, 1.0)// linear([p1, p2, p3, ...]) — values between 0 and 1
ease: 'linear(0, 0.5, 1)'
ease: 'linear(0, 0.2 25%, 0.8 75%, 1)'// linear([p1, p2, p3, ...]) — 值在0和1之间
ease: 'linear(0, 0.5, 1)'
ease: 'linear(0, 0.2 25%, 0.8 75%, 1)'// steps(n, direction)
ease: 'steps(5)'
ease: 'steps(5, start)' // 'start'|'end'|'both'|'none'// steps(n, direction)
ease: 'steps(5)'
ease: 'steps(5, start)' // 'start'|'end'|'both'|'none'import { createIrregular } from 'animejs';
ease: createIrregular(/* seed, amplitude, frequency */);import { createIrregular } from 'animejs';
ease: createIrregular(/* seed, amplitude, frequency */);import { createSpring } from 'animejs';
ease: createSpring({
mass: 1, // object mass
stiffness: 100, // spring stiffness
damping: 10, // damping coefficient
velocity: 0, // initial velocity
});
// or shorthand string
ease: 'spring(mass, stiffness, damping, velocity)'
ease: 'spring(1, 100, 10, 0)'
// outSpring (damped, comes to rest)
ease: 'outSpring'
ease: 'outSpring(stiffness, damping)'import { createSpring } from 'animejs';
ease: createSpring({
mass: 1, // 对象质量
stiffness: 100, // 弹簧刚度
damping: 10, // 阻尼系数
velocity: 0, // 初始速度
});
// 或简写字符串
ease: 'spring(mass, stiffness, damping, velocity)'
ease: 'spring(1, 100, 10, 0)'
// outSpring(阻尼,最终静止)
ease: 'outSpring'
ease: 'outSpring(stiffness, damping)'import {
$, get, set, cleanInlineStyles, remove, sync, keepTime,
random, createSeededRandom, randomPick, shuffle,
round, clamp, snap, wrap, mapRange, lerp, damp,
roundPad, padStart, padEnd, degToRad, radToDeg,
utils,
} from 'animejs';
// DOM
$('.selector') // querySelectorAll -> array
get(target, 'x') // get the current value of a property
set(target, { x: 100 }) // set value instantly
cleanInlineStyles(target) // remove inline styles left by animations
remove(target) // remove target from all active animations
sync(fn) // run fn on the next engine frame
keepTime(timer) // preserve timer time on revert
// Numbers
random(0, 100) // random number between min and max
random(0, 100, 2) // with decimal places
createSeededRandom(seed) // reproducible random generator -> fn()
randomPick([a, b, c]) // pick a random element from an array
shuffle([1, 2, 3, 4]) // shuffle array in place (mutates)
round(3.1415, 2) // -> 3.14
clamp(value, min, max) // clamp value to range
snap(value, increment) // round to nearest increment
snap(value, [0,50,100]) // round to nearest value in array
wrap(value, min, max) // wrap value within range (modulo)
mapRange(value, inMin, inMax, outMin, outMax) // remap a value between ranges
lerp(a, b, t) // linear interpolation
damp(current, target, lambda, dt) // smooth damp (frame-rate independent)
roundPad(value, decimals) // round with trailing zeros: 1.5 -> "1.50"
padStart(str, length, char) // pad left
padEnd(str, length, char) // pad right
degToRad(180) // -> Math.PI
radToDeg(Math.PI) // -> 180
// Chain-able utilities
utils(value)
.round(2)
.clamp(0, 100)
.mapRange(0, 100, 0, 1)
.get() // get final valueimport {
$, get, set, cleanInlineStyles, remove, sync, keepTime,
random, createSeededRandom, randomPick, shuffle,
round, clamp, snap, wrap, mapRange, lerp, damp,
roundPad, padStart, padEnd, degToRad, radToDeg,
utils,
} from 'animejs';
// DOM相关
$('.selector') // querySelectorAll -> 数组
get(target, 'x') // 获取属性当前值
set(target, { x: 100 }) // 立即设置值
cleanInlineStyles(target) // 移除动画留下的内联样式
remove(target) // 从所有活跃动画中移除目标元素
sync(fn) // 在下一引擎帧运行fn
keepTime(timer) // 还原时保留计时器时间
// 数字相关
random(0, 100) // 0到100之间的随机数
random(0, 100, 2) // 指定小数位数
createSeededRandom(seed) // 可复现的随机生成器 -> fn()
randomPick([a, b, c]) // 从数组中随机选取元素
shuffle([1, 2, 3, 4]) // 原地打乱数组(会修改原数组)
round(3.1415, 2) // -> 3.14
clamp(value, min, max) // 将值限制在范围内
snap(value, increment) // 四舍五入到指定增量
snap(value, [0,50,100]) // 四舍五入到数组中的最近值
wrap(value, min, max) // 将值包裹在范围内(取模)
mapRange(value, inMin, inMax, outMin, outMax) // 将值在两个范围间映射
lerp(a, b, t) // 线性插值
damp(current, target, lambda, dt) // 平滑阻尼(帧率无关)
roundPad(value, decimals) // 四舍五入并补零:1.5 -> "1.50"
padStart(str, length, char) // 左侧补全
padEnd(str, length, char) // 右侧补全
degToRad(180) // -> Math.PI
radToDeg(Math.PI) // -> 180
// 链式工具函数
utils(value)
.round(2)
.clamp(0, 100)
.mapRange(0, 100, 0, 1)
.get() // 获取最终值import { waapi } from 'animejs';
// waapi.animate() — same API as animate() but uses WAAPI internally
waapi.animate('.box', {
x: 200,
opacity: 0,
duration: 1000,
ease: 'outExpo',
});
// Improvements over native WAAPI:
// - Sensible defaults
// - Multi-target support
// - Automatic units (no explicit 'px' needed)
// - Function-based values
// - Individual CSS transforms (x, y, rotate, scale...)
// - Per-property parameters
// - Spring and custom easings
// API differences vs native WAAPI:
// loop -> iterations
// alternate -> direction: 'alternate'
// ease -> easing
// .then() -> .finished
// Convert anime.js easing to WAAPI format
const easing = waapi.convertEase('outElastic(1, .5)');
// -> CustomEffect function for use in native WAAPIimport { waapi } from 'animejs';
// waapi.animate() — 与animate()API相同,但内部使用WAAPI
waapi.animate('.box', {
x: 200,
opacity: 0,
duration: 1000,
ease: 'outExpo',
});
// 相比原生WAAPI的改进:
// - 合理的默认值
// - 多目标支持
// - 自动单位(无需显式'px')
// - 基于函数的取值
// - 独立CSS变换(x、y、rotate、scale...)
// 按属性设置参数
// - 弹簧和自定义缓动
// 与原生WAAPI的API差异:
// loop -> iterations
// alternate -> direction: 'alternate'
// ease -> easing
// .then() -> .finished
// 将anime.js缓动转换为WAAPI格式
const easing = waapi.convertEase('outElastic(1, .5)');
// -> 用于原生WAAPI的CustomEffect函数| Use WAAPI when... | Use JS engine when... |
|---|---|
| Only transforms and opacity | Color animations |
| Maximum performance matters | JS objects / custom properties |
| You don't need JS callbacks | You need precise onUpdate |
| GPU-accelerated properties | Layout / scroll sync |
| 使用WAAPI的场景 | 使用JS引擎的场景 |
|---|---|
| 仅处理变换和透明度 | 颜色动画 |
| 追求极致性能 | JS对象/自定义属性 |
| 不需要JS回调 | 需要精确的onUpdate |
| GPU加速属性 | 布局/滚动同步 |
import { engine } from 'animejs';
// Parameters (configure the global engine)
engine.timeUnit = 'ms'; // 'ms' | 's' — time unit (ms by default)
engine.speed = 1; // global speed multiplier
engine.fps = 60; // global max FPS
engine.precision = 4; // decimal precision
engine.pauseOnDocumentHidden = true; // pause when the tab is hidden
// Methods
engine.update(); // manually advance the engine (manual mode)
engine.pause(); // pause all timers/animations
engine.resume(); // resume the engine
// Properties
engine.currentTime // current engine time
engine.paused // boolean
// Defaults — global default values
engine.defaults.duration = 400;
engine.defaults.ease = 'outQuad';
// ... any animation/playback parameterimport { engine } from 'animejs';
// 参数(配置全局引擎)
engine.timeUnit = 'ms'; // 'ms' | 's' — 时间单位(默认ms)
engine.speed = 1; // 全局速度乘数
engine.fps = 60; // 全局最大帧率
engine.precision = 4; // 小数精度
engine.pauseOnDocumentHidden = true; // 标签页隐藏时暂停
// 方法
engine.update(); // 手动推进引擎(手动模式)
engine.pause(); // 暂停所有计时器/动画
engine.resume(); // 恢复引擎
// 属性
engine.currentTime // 当前引擎时间
engine.paused // 布尔值
// 默认值 — 全局默认参数
engine.defaults.duration = 400;
engine.defaults.ease = 'outQuad';
// ... 任何动画/播放参数import { animate } from 'animejs';
animate('.box', {
x: 250,
duration: 800,
ease: 'inOutExpo',
loop: true,
alternate: true,
});import { animate } from 'animejs';
animate('.box', {
x: 250,
duration: 800,
ease: 'inOutExpo',
loop: true,
alternate: true,
});import { createTimeline, stagger } from 'animejs';
createTimeline({ loop: true })
.add('.logo', { opacity: [0,1], y: [-20,0], duration: 600 })
.add('.title', { opacity: [0,1], x: [-30,0], delay: stagger(50) })
.add('.cta', { scale: [0.8,1], opacity: [0,1] }, '-=200');import { createTimeline, stagger } from 'animejs';
createTimeline({ loop: true })
.add('.logo', { opacity: [0,1], y: [-20,0], duration: 600 })
.add('.title', { opacity: [0,1], x: [-30,0], delay: stagger(50) })
.add('.cta', { scale: [0.8,1], opacity: [0,1] }, '-=200');import { animate, onScroll } from 'animejs';
animate('.parallax', {
y: ['-20%', '20%'],
ease: 'linear',
autoplay: onScroll({ sync: true }),
});import { animate, onScroll } from 'animejs';
animate('.parallax', {
y: ['-20%', '20%'],
ease: 'linear',
autoplay: onScroll({ sync: true }),
});import { splitText, animate, stagger } from 'animejs';
const { chars } = splitText('.hero-title', { chars: true });
animate(chars, {
opacity: [0, 1],
y: [30, 0],
rotateX: [-90, 0],
delay: stagger(40, { from: 'center' }),
duration: 700,
ease: 'outBack',
});import { splitText, animate, stagger } from 'animejs';
const { chars } = splitText('.hero-title', { chars: true });
animate(chars, {
opacity: [0, 1],
y: [30, 0],
rotateX: [-90, 0],
delay: stagger(40, { from: 'center' }),
duration: 700,
ease: 'outBack',
});import { animate, createDrawable, onScroll, stagger } from 'animejs';
animate(createDrawable('path'), {
draw: ['0 0', '0 1'],
delay: stagger(40),
ease: 'inOut(3)',
autoplay: onScroll({ sync: true }),
});import { animate, createDrawable, onScroll, stagger } from 'animejs';
animate(createDrawable('path'), {
draw: ['0 0', '0 1'],
delay: stagger(40),
ease: 'inOut(3)',
autoplay: onScroll({ sync: true }),
});import { createDraggable, createSpring } from 'animejs';
createDraggable('.card', {
container: '.board',
snap: 100,
releaseEase: createSpring({ stiffness: 200, damping: 20 }),
});import { createDraggable, createSpring } from 'animejs';
createDraggable('.card', {
container: '.board',
snap: 100,
releaseEase: createSpring({ stiffness: 200, damping: 20 }),
});import { createScope, createTimeline, stagger } from 'animejs';
createScope({
mediaQueries: { mobile: '(max-width: 768px)' },
}).add(({ matches }) => {
createTimeline()
.add('.nav-item', {
x: matches.mobile ? ['-100%', 0] : [0, 0],
y: matches.mobile ? 0 : [-20, 0],
delay: stagger(60),
});
});import { createScope, createTimeline, stagger } from 'animejs';
createScope({
mediaQueries: { mobile: '(max-width: 768px)' },
}).add(({ matches }) => {
createTimeline()
.add('.nav-item', {
x: matches.mobile ? ['-100%', 0] : [0, 0],
y: matches.mobile ? 0 : [-20, 0],
delay: stagger(60),
});
});import { animate, stagger } from 'animejs';
animate('.cell', {
scale: [0, 1],
delay: stagger(50, {
grid: [10, 10],
from: 'center',
}),
duration: 600,
ease: 'outBack',
});import { animate, stagger } from 'animejs';
animate('.cell', {
scale: [0, 1],
delay: stagger(50, {
grid: [10, 10],
from: 'center',
}),
duration: 600,
ease: 'outBack',
});import { createAnimatable } from 'animejs';
const blob = createAnimatable('.blob', {
x: { duration: 800, ease: 'outExpo' },
y: { duration: 800, ease: 'outExpo' },
});
document.addEventListener('mousemove', (e) => {
blob.x(e.clientX - 50);
blob.y(e.clientY - 50);
});import { createAnimatable } from 'animejs';
const blob = createAnimatable('.blob', {
x: { duration: 800, ease: 'outExpo' },
y: { duration: 800, ease: 'outExpo' },
});
document.addEventListener('mousemove', (e) => {
blob.x(e.clientX - 50);
blob.y(e.clientY - 50);
});| Value | Behaviour |
|---|---|
| Replaces the current animation |
| Adds to the current value (accumulates) |
| Smoothly blends with the current animation |
// Blend composition for interactive transforms
animate('.el', {
x: mouseX,
composition: 'blend',
});| 值 | 行为 |
|---|---|
| 替换当前动画 |
| 叠加到当前值(累积) |
| 与当前动画平滑混合 |
// 交互式变换使用混合合成
animate('.el', {
x: mouseX,
composition: 'blend',
});| Resource | URL |
|---|---|
| Official documentation | https://animejs.com/documentation |
| Easings editor | https://animejs.com/easing-editor |
| CodePen examples | https://codepen.io/collection/Poerqa |
| GitHub | https://github.com/juliangarnier/anime |
| npm | https://www.npmjs.com/package/animejs |