动画播放器 SDK
一个强大、灵活的Web动画播放器SDK,支持基于关键帧的复杂动画制作和播放。
🚀 功能特性
- 关键帧动画: 基于时间轴的关键帧动画系统
- 模板引擎: 支持
{{variable}}语法的动态内容渲染
- 事件系统: 完整的动画生命周期和元素交互事件支持
- CSS变换: 支持位移、缩放、旋转、透明度等动画属性
- 缓动函数: 内置多种缓动函数,包括弹性和弹跳效果
- 状态管理: 完整的播放、暂停、停止、跳转控制
- 自适应时长: 根据关键帧自动计算动画时长
- 类型安全: 完整的TypeScript类型定义
📦 安装
npm install @yqg-max/click-gate
🏗️ 核心接口
IAnimationElement
动画元素配置接口,定义了动画中每个元素的基本信息和样式。
interface IAnimationElement {
id: string;
data?: Record<string, any>;
content: {
html?: string;
style?: Record<string, string | number>;
};
}
IPropertieCss
CSS属性接口,定义了动画中常用的CSS变换属性。
interface IPropertieCss {
x: number;
y: number;
width: number;
height: number;
rotation: number;
opacity: number;
scale: number;
}
IAnimationKeyframe
动画关键帧接口,定义了某个时间点上元素的属性状态。
interface IAnimationKeyframe {
id: string;
elementId: string;
time: number;
properties: Partial<IPropertieCss> & Record<string, any>;
}
IAnimationSchema
动画配置模式接口,定义了完整的动画配置。
interface IAnimationSchema {
elements: IAnimationElement[];
keyframes: IAnimationKeyframe[];
data?: Record<string, any>;
}
IAnimationInfo
动画信息接口,提供动画的统计信息。
interface IAnimationInfo {
totalDuration: number;
maxKeyframeTime: number;
keyframeCount: number;
elementCount: number;
isAutoCalculated: boolean;
}
🎭 类型定义
EasingFunction
动画缓动函数类型。
type EasingFunction =
| 'linear'
| 'ease-in'
| 'ease-out'
| 'ease-in-out'
| 'ease-in-cubic'
| 'ease-out-cubic'
| 'bounce-out'
| 'elastic-out';
AnimationState
动画状态类型。
type AnimationState = 'idle' | 'playing' | 'paused' | 'completed';
ElementEventCallback
事件监听器回调函数类型。
type ElementEventCallback = (event: Event, element: HTMLElement) => void;
🎨 核心类
AnimationPlayer
动画播放器主类,负责管理和控制动画的播放。
构造函数
constructor(container: HTMLElement, schema: IAnimationSchema)
播放控制方法
play() | 开始播放动画 | - | void |
pause() | 暂停动画 | - | void |
stop() | 停止动画并重置到初始状态 | - | void |
seek(time: number) | 跳转到指定时间 | time: 目标时间(毫秒) | void |
状态查询方法
getCurrentTime() | 获取当前播放时间 | number |
getDuration() | 获取动画总时长 | number |
getProgress() | 获取播放进度(0-1) | number |
getState() | 获取当前状态 | AnimationState |
isPlaying() | 检查是否正在播放 | boolean |
getSchema() | 获取动画配置的副本 | IAnimationSchema |
getAnimationInfo() | 获取动画统计信息 | IAnimationInfo |
数据更新方法
updateData(newData) | 更新动画数据 | newData: 新数据对象 |
updateSchema(newSchema) | 更新动画配置 | newSchema: 新配置对象 |
事件监听方法
onTimeChange(callback) | 监听时间变化 | callback: (time: number) => void |
onAnimationComplete(callback) | 监听动画完成 | callback: () => void |
onStateChange(callback) | 监听状态变化 | callback: (state: AnimationState) => void |
onListen(elementId, eventType, callback) | 监听元素事件 | 详见下表 |
onListen 参数详情
elementId | string | 元素ID |
eventType | string | 事件类型('click', 'mouseover'等) |
callback | ElementEventCallback | 事件回调函数 |
| 返回值 | () => void | 取消监听的函数 |
事件管理方法
removeAllListeners(elementId) | 移除指定元素的所有事件监听器 | elementId: 元素ID |
removeAllElementListeners() | 移除所有事件监听器 | - |
destroy() | 销毁动画播放器 | - |
TemplateEngine
模板引擎类,负责解析和渲染模板字符串。
静态方法
render(template, data) | 渲染模板字符串 | template: 模板字符串
data: 渲染数据 | string |
CSSAnimationGenerator
CSS动画生成器类,负责生成CSS关键帧动画代码。
静态方法
generateKeyframes(elementId, keyframes) | 生成CSS关键帧动画 | elementId: 元素ID
keyframes: 关键帧数组 | string |
generateAnimationCSS(elementId, duration, easing) | 生成元素动画CSS | elementId: 元素ID
duration: 动画时长
easing: 缓动函数 | string |
easingToCSSFunction(easing) | 转换缓动函数为CSS | easing: 缓动函数名 | string |
🏭 工厂函数
createAnimationPlayer
根据容器ID创建动画播放器。
function createAnimationPlayer(
containerId: string,
schema: IAnimationSchema,
): AnimationPlayer;
createAnimationPlayerFromElement
直接使用DOM元素创建动画播放器。
function createAnimationPlayerFromElement(
container: HTMLElement,
schema: IAnimationSchema,
): AnimationPlayer;
🎯 快速开始
基础示例
import { createAnimationPlayer, IAnimationSchema } from '@yqg-max/click-gate';
const schema: IAnimationSchema = {
elements: [
{
id: 'box1',
content: {
html: '<div style="width: 100px; height: 100px; background: #3b82f6;"></div>',
style: {
borderRadius: '8px',
},
},
},
],
keyframes: [
{
id: 'kf1',
elementId: 'box1',
time: 0,
properties: { x: 0, y: 0, opacity: 1, scale: 1 },
},
{
id: 'kf2',
elementId: 'box1',
time: 1000,
properties: { x: 200, y: 100, opacity: 0.5, scale: 1.5 },
},
{
id: 'kf3',
elementId: 'box1',
time: 2000,
properties: { x: 0, y: 0, opacity: 1, scale: 1, rotation: 360 },
},
],
};
const player = createAnimationPlayer('animation-container', schema);
player.play();
模板渲染示例
const schema: IAnimationSchema = {
data: {
title: '欢迎使用动画播放器',
subtitle: '强大而灵活的动画解决方案',
},
elements: [
{
id: 'text1',
data: {
content: '{{title}}',
},
content: {
html: '<h2>{{content}}</h2>',
style: {
color: '#1f2937',
fontFamily: 'Arial, sans-serif',
},
},
},
{
id: 'text2',
content: {
html: '<p>{{subtitle}}</p>',
style: {
color: '#6b7280',
},
},
},
],
keyframes: [
{
id: 'title-start',
elementId: 'text1',
time: 0,
properties: { x: -200, opacity: 0 },
},
{
id: 'title-end',
elementId: 'text1',
time: 800,
properties: { x: 0, opacity: 1 },
},
{
id: 'subtitle-start',
elementId: 'text2',
time: 400,
properties: { x: 200, opacity: 0 },
},
{
id: 'subtitle-end',
elementId: 'text2',
time: 1200,
properties: { x: 0, opacity: 1 },
},
],
};
事件监听示例
const player = createAnimationPlayer('container', schema);
const removeClickListener = player.onListen(
'button1',
'click',
(event, element) => {
console.log('按钮被点击了!', element);
player.seek(1500);
},
);
player.onListen('image1', 'mouseover', (event, element) => {
element.style.transform = 'scale(1.1)';
});
player.onListen('image1', 'mouseout', (event, element) => {
element.style.transform = 'scale(1)';
});
player.onStateChange((state) => {
console.log('动画状态:', state);
});
player.onTimeChange((time) => {
console.log('当前时间:', time);
});
player.onAnimationComplete(() => {
console.log('动画播放完成!');
});
动态数据更新示例
const schema: IAnimationSchema = {
data: {
username: 'User',
score: 0,
},
elements: [
{
id: 'scoreDisplay',
content: {
html: '<div class="score">{{username}}的分数: {{score}}</div>',
},
},
],
keyframes: [
{
id: 'score-anim',
elementId: 'scoreDisplay',
time: 0,
properties: { scale: 1 },
},
{
id: 'score-bounce',
elementId: 'scoreDisplay',
time: 500,
properties: { scale: 1.2 },
},
{
id: 'score-normal',
elementId: 'scoreDisplay',
time: 1000,
properties: { scale: 1 },
},
],
};
const player = createAnimationPlayer('container', schema);
function updateScore(newScore: number) {
player.updateData({ score: newScore });
player.seek(0);
player.play();
}
updateScore(100);
updateScore(250);
🎪 高级用法
复杂动画序列
const complexSchema: IAnimationSchema = {
elements: [
{ id: 'circle', content: { html: '<div class="circle"></div>' } },
{ id: 'square', content: { html: '<div class="square"></div>' } },
{ id: 'triangle', content: { html: '<div class="triangle"></div>' } },
],
keyframes: [
{
id: 'c1',
elementId: 'circle',
time: 0,
properties: { x: 0, y: 0, opacity: 0 },
},
{
id: 'c2',
elementId: 'circle',
time: 500,
properties: { x: 100, y: 0, opacity: 1 },
},
{
id: 'c3',
elementId: 'circle',
time: 1000,
properties: { x: 100, y: 100, rotation: 180 },
},
{
id: 'c4',
elementId: 'circle',
time: 1500,
properties: { x: 0, y: 100, scale: 1.5 },
},
{
id: 'c5',
elementId: 'circle',
time: 2000,
properties: { x: 0, y: 0, scale: 1, rotation: 360 },
},
{
id: 's1',
elementId: 'square',
time: 300,
properties: { x: 200, y: 0, opacity: 0 },
},
{
id: 's2',
elementId: 'square',
time: 800,
properties: { x: 300, y: 0, opacity: 1 },
},
{
id: 's3',
elementId: 'square',
time: 1300,
properties: { x: 300, y: 100, rotation: 90 },
},
{
id: 's4',
elementId: 'square',
time: 1800,
properties: { x: 200, y: 100, scale: 0.8 },
},
{
id: 't1',
elementId: 'triangle',
time: 600,
properties: { x: 400, y: 50, opacity: 0 },
},
{
id: 't2',
elementId: 'triangle',
time: 1100,
properties: { x: 450, y: 50, opacity: 1 },
},
{
id: 't3',
elementId: 'triangle',
time: 1600,
properties: { x: 450, y: 100, rotation: 120 },
},
{
id: 't4',
elementId: 'triangle',
time: 2100,
properties: { x: 400, y: 100, scale: 1.2 },
},
],
};
自定义缓动函数
const bounceSchema: IAnimationSchema = {
elements: [{ id: 'bouncer', content: { html: '<div class="ball"></div>' } }],
keyframes: [
{
id: 'bounce-start',
elementId: 'bouncer',
time: 0,
properties: { y: 0 },
},
{
id: 'bounce-drop',
elementId: 'bouncer',
time: 1000,
properties: { y: 200 },
},
{
id: 'bounce-up',
elementId: 'bouncer',
time: 1500,
properties: { y: 50 },
},
{
id: 'bounce-settle',
elementId: 'bouncer',
time: 2000,
properties: { y: 200 },
},
],
};
📝 API 参考
动画播放器 API
播放控制
play() - 播放动画
pause() - 暂停动画
stop() - 停止动画
seek(time: number) - 跳转到指定时间
状态查询
getCurrentTime(): number - 当前播放时间
getDuration(): number - 动画总时长
getProgress(): number - 播放进度 (0-1)
getState(): AnimationState - 当前状态
isPlaying(): boolean - 是否正在播放
数据管理
updateData(data: Record<string, any>) - 更新动画数据
updateSchema(schema: IAnimationSchema) - 更新动画配置
getSchema(): IAnimationSchema - 获取当前配置
getAnimationInfo(): IAnimationInfo - 获取动画信息
事件监听
onTimeChange(callback) - 时间变化事件
onAnimationComplete(callback) - 动画完成事件
onStateChange(callback) - 状态变化事件
onListen(elementId, eventType, callback) - 元素事件监听
事件管理
removeAllListeners(elementId) - 移除指定元素的监听器
removeAllElementListeners() - 移除所有监听器
destroy() - 销毁播放器
🔧 最佳实践
1. 性能优化
const badSchema = {
keyframes: [
{ time: 0, properties: { x: 0 } },
{ time: 10, properties: { x: 1 } },
{ time: 20, properties: { x: 2 } },
],
};
const goodSchema = {
keyframes: [
{ time: 0, properties: { x: 0 } },
{ time: 500, properties: { x: 50 } },
{ time: 1000, properties: { x: 100 } },
],
};
2. 内存管理
const player = createAnimationPlayer('container', schema);
function cleanup() {
player.destroy();
}
useEffect(() => {
return () => {
cleanup();
};
}, []);
3. 错误处理
try {
const player = createAnimationPlayer('container', schema);
player.play();
} catch (error) {
console.error('动画初始化失败:', error);
}
⚠️ 注意事项
- 容器元素: 确保容器元素存在且已挂载到DOM
- 唯一ID: 元素ID和关键帧ID必须唯一
- 关键帧关联: 所有关键帧必须关联到存在的元素
- 内存清理: 使用完毕后调用
destroy()方法清理资源
- 时间单位: 所有时间参数使用毫秒为单位
- CSS属性: 支持的CSS属性有限,主要为变换属性
🐛 常见问题
Q: 动画不播放?
A: 检查以下几点:
- 容器元素是否存在
- 动画配置是否正确
- 是否有关键帧数据
- 检查浏览器控制台是否有错误
Q: 模板变量不显示?
A: 确保:
- 数据对象包含对应的属性
- 模板语法正确使用
{{variableName}}
- 调用
updateData()后重新渲染
Q: 事件监听器不工作?
A: 检查:
- 元素ID是否正确
- 事件类型名称是否正确
- 元素是否已创建并添加到DOM
📄 许可证
MIT License
🤝 贡献
欢迎提交 Issue 和 Pull Request!
如有疑问,请查看源码注释或提交 Issue。