关于 dotlottie-web
为 Web 项目集成 dotLottie 动画提供实现指南,涵盖通用 Web 与 React 包的选择。内容包括 Canvas 播放、Worker 渲染、多动画文件及常见交互模式。
主要功能
- 01Web 与 React 包的选择指南
- 02基于 Canvas 的动画播放
- 03Web Worker 渲染选项
- 04支持多动画 .lottie 文件
- 05播放与交互模式
适用场景
- 01为 Web 界面添加动画
- 02将复杂动画渲染移至 Worker
- 03构建悬停、点击或滚动控制的播放
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ lottiefiles/ dotlottie-web --skill dotlottie-web安装后在 Claude Code 中输入/dotlottie-web确认已加载。
详细介绍
dotLottie 实现指南
你是使用 dotLottie 运行时实现 Lottie 动画的专家。在 Web 项目中使用 dotLottie 时,请遵循以下指南。
选择软件包
在以下情况下使用 @lottiefiles/dotlottie-web:
- 需要直接控制 canvas
- 构建与框架无关的代码
- 性能至关重要
- 希望获得最小的打包体积
在以下情况下使用 @lottiefiles/dotlottie-react:
- 构建 React 应用
- 希望使用声明式组件 API
- 需要集成 React 生命周期
安装
# Web (vanilla JS, Vue, Svelte, etc.)
npm install @lottiefiles/dotlottie-web
# React
npm install @lottiefiles/dotlottie-react
基本实现
原生 JavaScript
import { DotLottie } from '@lottiefiles/dotlottie-web';
const dotLottie = new DotLottie({
canvas: document.getElementById('canvas') as HTMLCanvasElement,
src: 'https://example.com/animation.lottie',
autoplay: true,
loop: true,
});
React
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
function Animation() {
return (
<DotLottieReact
src="https://example.com/animation.lottie"
autoplay
loop
/>
);
}
使用实例控制的 React
import { useRef } from 'react';
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
import type { DotLottie } from '@lottiefiles/dotlottie-web';
function Animation() {
const dotLottieRef = useRef<DotLottie | null>(null);
return (
<DotLottieReact
src="https://example.com/animation.lottie"
dotLottieRefCallback={(dotLottie) => (dotLottieRef.current = dotLottie)}
/>
);
}
.lottie 与 .json
始终优先使用 .lottie 格式,而非 .json:
- 文件更小(经过压缩)
- 一个文件支持多个动画
- 内嵌资源(图像、字体)
- 支持用于交互的状态机
- 使用插槽进行主题设置
Web Worker(推荐用于提升性能)
使用 DotLottieWorker 将动画渲染移至 Web Worker,让主线程专注于 UI 交互:
Worker 基本用法
import { DotLottieWorker } from '@lottiefiles/dotlottie-web';
const dotLottie = new DotLottieWorker({
canvas: document.getElementById('canvas') as HTMLCanvasElement,
src: 'https://example.com/animation.lottie',
autoplay: true,
loop: true,
});
Worker 分组(多个动画)
默认情况下,所有 DotLottieWorker 实例共用同一个 worker。使用 workerId 将动画分组到不同的 worker:
// Hero animation in its own worker
const heroAnimation = new DotLottieWorker({
canvas: heroCanvas,
src: 'hero.lottie',
workerId: 'hero-worker',
});
// UI animations share a different worker
const buttonAnimation = new DotLottieWorker({
canvas: buttonCanvas,
src: 'button.lottie',
workerId: 'ui-worker',
});
何时使用 Worker
-
使用
DotLottieWorker:- 同时运行多个动画
- 包含许多图层的复杂动画
- 动画与占用大量资源的 JS 操作同时运行
- 主线程性能至关重要的移动设备
-
使用普通的
DotLottie:- 单个简单动画
- 需要同步访问帧
- SSR 环境(不提供 worker)
使用 Worker 的 React
import { DotLottieWorkerReact } from '@lottiefiles/dotlottie-react';
function Animation() {
return (
<DotLottieWorkerReact
src="animation.lottie"
autoplay
loop
workerId="my-worker" // Optional: dedicate to specific worker
/>
);
}
状态机(交互)
状态机无需编写代码即可实现交互式动画。详情请参阅状态机指南。
const dotLottie = new DotLottie({
canvas,
src: 'interactive.lottie', // Contains state machine
autoplay: true,
});
// Fire events to trigger state transitions
dotLottie.stateMachineFireEvent('click');
dotLottie.stateMachineFireEvent('hover');
dotLottie.stateMachineFireEvent('custom-event');
// Set numeric/boolean/string inputs for state conditions
// See: https://github.com/LottieFiles/dotlottie-web/wiki/dotLottie-State-Machine-Guide#working-with-inputs
dotLottie.stateMachineSetNumericInput('progress', 0.5);
dotLottie.stateMachineSetBooleanInput('isActive', true);
dotLottie.stateMachineSetStringInput('mode', 'dark');
状态机事件
click- 用户点击或轻触hover- 鼠标移入unhover- 鼠标移出complete- 动画播放完毕- 在状态机中定义的自定义事件
使用插槽设置主题
插槽支持在运行时自定义颜色或值。主题遵循 dotLottie 2.0 规范。
const dotLottie = new DotLottie({
canvas,
src: 'themed.lottie',
themeId: 'dark-mode', // Use embedded theme by ID
});
// Or apply theme data directly (JSON string per dotLottie 2.0 spec)
// See: https://dotlottie.io/spec/2.0/#themes
dotLottie.setThemeData(JSON.stringify({
rules: [
{ id: 'primary-color', value: [1, 0.34, 0.13] }, // RGB values 0-1
]
}));
动态覆盖插槽
插槽通过类型化 API 支持在运行时自定义动画属性。 可用插槽类型:颜色、标量、向量、渐变、文本、图像。
关键 API:getSlotIds()、getSlotType()、setColorSlot()、setScalarSlot()、
setVectorSlot()、setGradientSlot()、setTextSlot()、resetSlot()、clearSlots()。
如需查看完整的 API 参考,其中包含每种插槽类型的代码示例、动画关键帧、 重置、批量更新、常见用例(品牌设置、深色模式、进度指示器) 以及 React 集成,请参阅动态插槽参考。
标记与片段
播放指定片段
// Play frames 0-60
dotLottie.setSegment(0, 60);
dotLottie.play();
// Play by marker name (defined in animation)
dotLottie.setMarker('intro');
dotLottie.play();
获取标记
const markers = dotLottie.markers();
// Returns: [{ name: 'intro', start: 0, end: 60 }, ...]
将指定帧渲染为图像
设置 autoplay: false,避免播放超过目标帧;然后在 load 后调用 setFrame()。setFrame() 会同步渲染,因此调用后,canvas 和 dotLottie.buffer(RGBA Uint8Array)会立即保存该帧的内容。
浏览器
const dotLottie = new DotLottie({ canvas, src: 'animation.lottie', autoplay: false });
dotLottie.addEventListener('load', () => {
dotLottie.setFrame(42); // render frame 42
const dataUrl = canvas.toDataURL('image/png'); // or canvas.toBlob(cb, 'image/png')
});
Node.js(@napi-rs/canvas)
import fs from 'node:fs';
import { createCanvas } from '@napi-rs/canvas';
const canvas = createCanvas(200, 200);
const dotLottie = new DotLottie({
canvas: canvas as unknown as HTMLCanvasElement,
src: 'animation.lottie',
autoplay: false,
});
dotLottie.addEventListener('load', async () => {
dotLottie.setFrame(42);
fs.writeFileSync('frame-42.png', await canvas.encode('png'));
dotLottie.destroy();
});
如需自定义编码,可直接从 dotLottie.buffer 读取原始 RGBA 像素(长度 = width × height × 4)。
事件处理
dotLottie.addEventListener('load', () => {
console.log('Animation loaded');
});
dotLottie.addEventListener('play', () => {
console.log('Playing');
});
dotLottie.addEventListener('complete', () => {
console.log('Animation completed');
});
dotLottie.addEventListener('frame', ({ currentFrame }) => {
console.log('Frame:', currentFrame);
});
// Clean up
dotLottie.removeEventListener('load', handler);
性能最佳实践
1. 对复杂动画使用 Web Worker
import { DotLottieWorker } from '@lottiefiles/dotlottie-web';
// Offload rendering to worker thread
const dotLottie = new DotLottieWorker({
canvas,
src: 'complex-animation.lottie',
});
2. 延迟加载动画
// Only load when visible
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
loadAnimation();
observer.disconnect();
}
});
});
observer.observe(container);
3. 默认启用自动冻结
当动画不可见(位于视口之外)时,DotLottie 会自动冻结动画。要禁用此行为:
const dotLottie = new DotLottie({
canvas,
src: 'animation.lottie',
renderConfig: {
freezeOnOffscreen: false, // Disable auto-freeze (not recommended)
},
});
4. 设备像素比
默认情况下,devicePixelRatio 设置为实际值的 75%,以提升性能。若要获得完整的 Retina 画质(性能开销更高):
const dotLottie = new DotLottie({
canvas,
src: 'animation.lottie',
renderConfig: {
devicePixelRatio: window.devicePixelRatio, // Full retina (higher CPU/GPU)
},
});
5. 清理(仅原生 JS)
// Always destroy when done (vanilla JS)
dotLottie.destroy();
注意: DotLottieReact 会在卸载时自动处理清理,无需手动清理。
6. 帧插值控制
const dotLottie = new DotLottie({
canvas,
src: 'animation.lottie',
useFrameInterpolation: true, // Smooth playback (default)
// useFrameInterpolation: false, // Match original AE frame rate
});
多动画文件
单个 .lottie 文件可以包含多个动画:
// Load specific animation by ID
dotLottie.loadAnimation('animation-2');
// Get all animation IDs
const animations = dotLottie.manifest?.animations;
// Returns: [{ id: 'animation-1' }, { id: 'animation-2' }]
Canvas 尺寸
通过 CSS 样式设置 canvas 尺寸(推荐)。DotLottie 会自动确定最佳绘制区域:
<canvas id="canvas" style="width: 400px; height: 400px;"></canvas>
自动调整为容器尺寸
使用 autoResize 渲染配置,在容器发生变化时自动调整尺寸:
const dotLottie = new DotLottie({
canvas,
src: 'animation.lottie',
renderConfig: {
autoResize: true, // Canvas resizes to fit container
},
});
常见模式
悬停时播放
canvas.addEventListener('mouseenter', () => dotLottie.play());
canvas.addEventListener('mouseleave', () => dotLottie.pause());
点击时播放(一次)
canvas.addEventListener('click', () => {
dotLottie.setFrame(0);
dotLottie.setLoop(false);
dotLottie.play();
});
随滚动位置播放
window.addEventListener('scroll', () => {
const progress = window.scrollY / (document.body.scrollHeight - window.innerHeight);
const frame = progress * dotLottie.totalFrames;
dotLottie.setFrame(frame);
});
加载状态(React)
function Animation() {
const [isLoaded, setIsLoaded] = useState(false);
return (
<>
{!isLoaded && <Skeleton />}
<DotLottieReact
src="animation.lottie"
style={{ opacity: isLoaded ? 1 : 0 }}
dotLottieRefCallback={(dotLottie) => {
dotLottie.addEventListener('load', () => setIsLoaded(true));
}}
/>
</>
);
}
响应式动画
function ResponsiveAnimation() {
return (
<DotLottieReact
src="animation.lottie"
autoplay
loop
style={{ width: '100%', maxWidth: '400px' }}
renderConfig={{ autoResize: true }}
/>
);
}
调试
// Check if loaded
console.log('Loaded:', dotLottie.isLoaded);
// Get animation info
console.log('Duration:', dotLottie.duration);
console.log('Total Frames:', dotLottie.totalFrames);
console.log('Current Frame:', dotLottie.currentFrame);
console.log('Is Playing:', dotLottie.isPlaying);
console.log('Loop:', dotLottie.loop);
console.log('Speed:', dotLottie.speed);
// Get manifest (for .lottie files)
console.log('Manifest:', dotLottie.manifest);
错误处理
dotLottie.addEventListener('loadError', (error) => {
console.error('Failed to load animation:', error);
// Show fallback UI
});
SSR / Next.js 注意事项
dotLottie 需要浏览器 API。对于 SSR 框架:
import dynamic from 'next/dynamic';
const DotLottieReact = dynamic(
() => import('@lottiefiles/dotlottie-react').then(mod => mod.DotLottieReact),
{ ssr: false }
);
function Animation() {
return <DotLottieReact src="animation.lottie" autoplay loop />;
}
资源
- 文档:https://developers.lottiefiles.com/docs/dotlottie-player
- 状态机指南:https://github.com/LottieFiles/dotlottie-web/wiki/dotLottie-State-Machine-Guide
- GitHub:https://github.com/LottieFiles/dotlottie-web
- dotLottie 2.0 规范:https://dotlottie.io/spec/2.0/
- 创建 .lottie 文件:https://lottiefiles.com 或 https://creators.lottiefiles.com