anime.js 黄色圆点 · 进阶游乐场
上动画 · 下代码 · 一行三列 · 深入 anime.js 的进阶能力
基础强化
时间线控制 timeline
使用 anime.timeline 串联多个动画:缩放 → 位移 → 旋转 → 归位,精确控制次序与重叠。
// 时间线串联
const tl = anime.timeline({
loop: true,
easing: ‘easeInOutQuad’,
duration: 600
});
tl.add({ targets: ‘#dot-timeline’, scale: 1.5 })
.add({ targets: ‘#dot-timeline’, translateX: 50 })
.add({ targets: ‘#dot-timeline’, rotate: 180 })
.add({ targets: ‘#dot-timeline’, translateX: 0, rotate: 360, scale: 1 });
const tl = anime.timeline({
loop: true,
easing: ‘easeInOutQuad’,
duration: 600
});
tl.add({ targets: ‘#dot-timeline’, scale: 1.5 })
.add({ targets: ‘#dot-timeline’, translateX: 50 })
.add({ targets: ‘#dot-timeline’, rotate: 180 })
.add({ targets: ‘#dot-timeline’, translateX: 0, rotate: 360, scale: 1 });
SVG 路径跟随 motionPath
让圆点沿着 SVG 路径移动。anime 的 motionPath 插件功能,实现复杂的曲线运动。
// 需要 anime.js motionPath 插件(此处用内置 path 支持)
anime({
targets: ‘#dot-svg-path’,
translateX: [0, 80, 160],
translateY: [0, –40, 0],
duration: 2400,
loop: true,
direction: ‘alternate’,
easing: ‘easeInOutSine’
});
// 更精确可用 anime.path() 配合 CSS 路径
anime({
targets: ‘#dot-svg-path’,
translateX: [0, 80, 160],
translateY: [0, –40, 0],
duration: 2400,
loop: true,
direction: ‘alternate’,
easing: ‘easeInOutSine’
});
// 更精确可用 anime.path() 配合 CSS 路径
拖尾跟随 delay + stagger
主圆点移动,三个小圆点依次延迟跟随,形成弹性拖尾效果。使用 stagger 和 translate 组合。
// 拖尾 (简化: 相对位移延迟)
anime({
targets: [‘#dot-lead’, ‘#dot-follow1’, ‘#dot-follow2’, ‘#dot-follow3’],
translateX: [0, 60, 0],
translateY: [0, –30, 0],
duration: 1600,
delay: anime.stagger(120),
loop: true,
easing: ‘easeInOutQuad’
});
anime({
targets: [‘#dot-lead’, ‘#dot-follow1’, ‘#dot-follow2’, ‘#dot-follow3’],
translateX: [0, 60, 0],
translateY: [0, –30, 0],
duration: 1600,
delay: anime.stagger(120),
loop: true,
easing: ‘easeInOutQuad’
});
复杂动画 · 进阶技巧
网格波浪 grid + stagger
4×4 圆点阵,按照网格位置错峰缩放,形成波浪扩散。使用 anime.stagger 的 grid 与 from 参数。
// 网格波浪
anime({
targets: ‘#dot-grid-wave .dot’,
scale: [
{ value: 0.5, duration: 400 },
{ value: 1, duration: 800 }
],
delay: anime.stagger(80, {
grid: [4, 4],
from: ‘center’
}),
loop: true,
direction: ‘alternate’,
easing: ‘easeInOutQuad’
});
anime({
targets: ‘#dot-grid-wave .dot’,
scale: [
{ value: 0.5, duration: 400 },
{ value: 1, duration: 800 }
],
delay: anime.stagger(80, {
grid: [4, 4],
from: ‘center’
}),
loop: true,
direction: ‘alternate’,
easing: ‘easeInOutQuad’
});
3D 翻转 rotateY + perspective
圆点沿 Y 轴翻转,结合 perspective 与 scale 产生立体感。anime 支持所有 CSS transform 属性。
// 3D 翻转 (需父级 perspective)
anime({
targets: ‘#dot-3d-flip’,
rotateY: [0, 180, 360],
scale: [1, 1.2, 1],
duration: 2000,
loop: true,
easing: ‘easeInOutQuad’
});
anime({
targets: ‘#dot-3d-flip’,
rotateY: [0, 180, 360],
scale: [1, 1.2, 1],
duration: 2000,
loop: true,
easing: ‘easeInOutQuad’
});
多段关键帧 keyframes + 缓动
圆点走一个矩形轨迹,每段使用不同缓动,最后旋转归位。keyframes 可指定每帧缓动。
// 多段关键帧 + 独立缓动
anime({
targets: ‘#dot-complex’,
keyframes: [
{ translateX: 50, easing: ‘easeOutQuad’ },
{ translateY: 40, easing: ‘easeInQuad’ },
{ translateX: 0, easing: ‘easeOutQuad’ },
{ translateY: 0, easing: ‘easeInQuad’ }
],
rotate: [0, 180],
duration: 2400,
loop: true,
direction: ‘alternate’
});
anime({
targets: ‘#dot-complex’,
keyframes: [
{ translateX: 50, easing: ‘easeOutQuad’ },
{ translateY: 40, easing: ‘easeInQuad’ },
{ translateX: 0, easing: ‘easeOutQuad’ },
{ translateY: 0, easing: ‘easeInQuad’ }
],
rotate: [0, 180],
duration: 2400,
loop: true,
direction: ‘alternate’
});
创意动画 · 视觉表现
弹跳 & 挤压 scaleX/scaleY
模拟重力弹跳,落地时横向拉伸、纵向压缩,升起时恢复。组合 scaleX 和 scaleY 与 translateY。
// 弹跳 + 挤压拉伸
anime({
targets: ‘#dot-bounce’,
translateY: [
{ value: –50, duration: 500, easing: ‘easeOutQuad’ },
{ value: 0, duration: 400, easing: ‘easeInQuad’ }
],
scaleY: [
{ value: 1.2, duration: 200 },
{ value: 0.8, duration: 200 },
{ value: 1, duration: 300 }
],
scaleX: [
{ value: 0.9, duration: 200 },
{ value: 1.1, duration: 200 },
{ value: 1, duration: 300 }
],
loop: true,
easing: ‘easeInOutQuad’
});
anime({
targets: ‘#dot-bounce’,
translateY: [
{ value: –50, duration: 500, easing: ‘easeOutQuad’ },
{ value: 0, duration: 400, easing: ‘easeInQuad’ }
],
scaleY: [
{ value: 1.2, duration: 200 },
{ value: 0.8, duration: 200 },
{ value: 1, duration: 300 }
],
scaleX: [
{ value: 0.9, duration: 200 },
{ value: 1.1, duration: 200 },
{ value: 1, duration: 300 }
],
loop: true,
easing: ‘easeInOutQuad’
});
圆周环绕 rotate + translate
四个小圆点绕中心旋转,每个相位相差 90 度。组合 rotate 和 translate 产生环绕效果。
// 环绕 (每个圆点独立动画)
const radius = 40;
[‘#orbit1’, ‘#orbit2’, ‘#orbit3’, ‘#orbit4’].forEach((id, i) => {
anime({
targets: id,
rotate: [0, 360],
translateX: {
value: radius,
duration: 2000,
easing: ‘linear’
},
translateY: {
value: 0,
duration: 2000,
easing: ‘linear’
},
delay: i * 500,
loop: true
});
});
// 实际简化为 translateX/Y 配合 rotate 产生圆周效果
const radius = 40;
[‘#orbit1’, ‘#orbit2’, ‘#orbit3’, ‘#orbit4’].forEach((id, i) => {
anime({
targets: id,
rotate: [0, 360],
translateX: {
value: radius,
duration: 2000,
easing: ‘linear’
},
translateY: {
value: 0,
duration: 2000,
easing: ‘linear’
},
delay: i * 500,
loop: true
});
});
// 实际简化为 translateX/Y 配合 rotate 产生圆周效果
0
数值动画 anime counter
下方数字从 0 增长到 100,同时上方圆点数量随之变化。anime 可动画任意 JS 对象属性。
// 数值动画 + 圆点联动
const obj = { value: 0 };
anime({
targets: obj,
value: 100,
round: 1,
duration: 3000,
loop: true,
direction: ‘alternate’,
easing: ‘easeInOutQuad’,
update: function() {
// 更新数字显示
document.getElementById(‘counter-value’).textContent = obj.value;
// 根据数值改变圆点透明度或缩放
const dots = document.querySelectorAll(‘#digit-dots .dot’);
dots.forEach((dot, i) => {
dot.style.opacity = obj.value > (i * 20) ? 1 : 0.2;
});
}
});
const obj = { value: 0 };
anime({
targets: obj,
value: 100,
round: 1,
duration: 3000,
loop: true,
direction: ‘alternate’,
easing: ‘easeInOutQuad’,
update: function() {
// 更新数字显示
document.getElementById(‘counter-value’).textContent = obj.value;
// 根据数值改变圆点透明度或缩放
const dots = document.querySelectorAll(‘#digit-dots .dot’);
dots.forEach((dot, i) => {
dot.style.opacity = obj.value > (i * 20) ? 1 : 0.2;
});
}
});
超复杂 · 综合运用
螺旋扩散 stagger + 3D
五个圆点从中心螺旋扩散,每个圆点沿不同角度移动,形成旋转飞散效果,使用独立延迟。
// 螺旋扩散
const angles = [0, 72, 144, 216, 288];
angles.forEach((angle, i) => {
const rad = angle * Math.PI / 180;
const r = 55;
anime({
targets: `#spiral${i+1}`,
translateX: Math.cos(rad) * r,
translateY: Math.sin(rad) * r,
scale: [0.5, 1.2, 0.5],
duration: 2000,
delay: i * 100,
loop: true,
direction: ‘alternate’,
easing: ‘easeInOutSine’
});
});
const angles = [0, 72, 144, 216, 288];
angles.forEach((angle, i) => {
const rad = angle * Math.PI / 180;
const r = 55;
anime({
targets: `#spiral${i+1}`,
translateX: Math.cos(rad) * r,
translateY: Math.sin(rad) * r,
scale: [0.5, 1.2, 0.5],
duration: 2000,
delay: i * 100,
loop: true,
direction: ‘alternate’,
easing: ‘easeInOutSine’
});
});
综合时间线 timeline + keyframes
用时间线串联弹跳、旋转、变色、阴影扩散,每个阶段精确控制时长与缓动,展示复杂编排。
// 综合时间线 (节选)
const tl2 = anime.timeline({ loop: true });
tl2.add({ targets: ‘#dot-master’, translateY: –40, duration: 400, easing: ‘easeOutQuad’ })
.add({ targets: ‘#dot-master’, translateY: 0, scaleY: 0.8, scaleX: 1.2, duration: 300, easing: ‘easeInQuad’ })
.add({ targets: ‘#dot-master’, scaleY: 1, scaleX: 1, duration: 200 })
.add({ targets: ‘#dot-master’, rotate: 180, backgroundColor: ‘#f0b83a’, duration: 600 })
.add({ targets: ‘#dot-master’, rotate: 360, backgroundColor: ‘#f7d117’, boxShadow: ‘0 0 30px 10px rgba(247,209,23,0.8)’, duration: 600 })
.add({ targets: ‘#dot-master’, boxShadow: ‘0 6px 12px rgba(247,209,23,0.3)’, duration: 400 });
const tl2 = anime.timeline({ loop: true });
tl2.add({ targets: ‘#dot-master’, translateY: –40, duration: 400, easing: ‘easeOutQuad’ })
.add({ targets: ‘#dot-master’, translateY: 0, scaleY: 0.8, scaleX: 1.2, duration: 300, easing: ‘easeInQuad’ })
.add({ targets: ‘#dot-master’, scaleY: 1, scaleX: 1, duration: 200 })
.add({ targets: ‘#dot-master’, rotate: 180, backgroundColor: ‘#f0b83a’, duration: 600 })
.add({ targets: ‘#dot-master’, rotate: 360, backgroundColor: ‘#f7d117’, boxShadow: ‘0 0 30px 10px rgba(247,209,23,0.8)’, duration: 600 })
.add({ targets: ‘#dot-master’, boxShadow: ‘0 6px 12px rgba(247,209,23,0.3)’, duration: 400 });
随机动画 random + update
每个圆点随机移动、旋转、缩放,每次循环随机生成新目标,利用 function-based values。
// 随机值 (每次循环随机)
anime({
targets: ‘#random-dots .dot’,
translateX: () => anime.random(-40, 40),
translateY: () => anime.random(-30, 30),
rotate: () => anime.random(0, 360),
scale: () => anime.random(0.5, 15) / 10,
duration: 2000,
delay: anime.stagger(100),
loop: true,
direction: ‘alternate’,
easing: ‘easeInOutQuad’
});
anime({
targets: ‘#random-dots .dot’,
translateX: () => anime.random(-40, 40),
translateY: () => anime.random(-30, 30),
rotate: () => anime.random(0, 360),
scale: () => anime.random(0.5, 15) / 10,
duration: 2000,
delay: anime.stagger(100),
loop: true,
direction: ‘alternate’,
easing: ‘easeInOutQuad’
});