lottie
Lottie是一款由airbnb开源的跨平台动画渲染库,支持Android, iOS, Web, Windows平台。是专门用于解析从AE(Adobe After Effects)中通过 Bodymovin 插件导出的JSON文件,直接渲染动画。
属性与方法
优缺点
优点:
- UI 同学通过 AE 制作动画,前端可以直接还原和控制,降低动画工作量;
- SVG 是可伸缩的,任何分辨率下都不会失真;
- JSON 文件大小会比 GIF 以及 APNG 等文件小很多,性能也会更好。
缺点:
- lottie-web 文件本身比较大,大小为 513KB,轻量版压缩后也有 144KB,经过 GZIP 后,大小为39k;
- 使用的 json 文件是由 AE 导出的,如果 UI 在设计的时候创建了很多图层,可能会导致 json 文件较大;
- 有部分 AE 动画的效果还不支持,lottie 无法实现或存在性能问题。
动画数据对象(json)结构
lottie-web 原理剖析
封装可复用 lottie 函数组件(React):
tsx
import React from 'react';
import lottie, { type AnimationItem } from 'lottie-web';
type RendererType = 'svg' | 'canvas' | 'html';
interface LottieProps {
// 是否循环播放
loop?: boolean;
// 渲染动画的类型
renderer?: RendererType;
// 是否自动播放
autoplay?: boolean;
// 动画渲染数据,与path互斥
animationData?: any;
// JSON文件路径,与animationData互斥
path?: string;
// 动画名称
name?: string;
}
/**
* 封装 lottie 函数组件
*/
const Lottie = React.forwardRef<
{
getInstance: () => AnimationItem | null;
play: () => void;
pause: () => void;
stop: () => void;
},
LottieProps
>((props, ref) => {
// 设置props的默认值
const { loop = true, renderer = 'svg', path = '', animationData, autoplay = true, name = 'anim' } = props;
const containerRef = React.useRef<HTMLDivElement | null>(null);
const animationItemRef = React.useRef<AnimationItem | null>(null);
// 暴露给从 props 传入的 ref 的方法
React.useImperativeHandle(ref, () => ({
// 获取当前动画对象实例
getInstance: () => animationItemRef.current,
// 播放,继续播放
play: () => {
animationItemRef.current?.play();
},
// 暂停动画
pause: () => {
animationItemRef.current?.pause();
},
// 停止动画,区别于暂停动画 pause()
stop: () => {
animationItemRef.current?.stop();
},
}));
// 缓存 lottie 动画参数
const animationParams = React.useMemo(
() =>
animationData ? { name, autoplay, loop, renderer, animationData } : { name, autoplay, loop, renderer, path },
[loop, renderer, autoplay, path, animationData, name]
);
React.useEffect(() => {
if (containerRef.current) {
animationItemRef.current = lottie.loadAnimation({
...animationParams,
container: containerRef.current,
});
}
return () => {
// 更新动画参数和卸载时,销毁动画对象,避免内存泄漏
animationItemRef.current?.destroy();
animationItemRef.current = null;
};
}, [animationParams]);
return (
// 渲染容器
<div ref={containerRef} style={{ width: '100%', height: '100%' }}></div>
);
});
export default Lottie;