都2022年了,一个还不知道Lottie动画的前端已经OUT啦!

这是一篇可以释放前端同学压力,解放人力,提高生产力的文章。

一、为什么会有Lottie动画呢?

在前端程序员根据UI视觉稿实现页面效果时一直存在这样的一种“矛盾” - 动画效果更完美与工期成本的矛盾。一般来说,页面中包含的动画效果越复杂,前端程序员在实现时需要的工期成本越大,尤其是在官网、大促活动、活动拉新等包含巨多动画效果的场景中,动画实现需要的时间占据了大部分工期时间,而工期往往是非常紧凑的。同时后期还经常伴随着与UI设计师的反复“拉扯” - 动画方向要改变下,运动的路径曲线要再调整下,这个圆角值不太圆,这个图片辛苦再替换下。诸如此类,都是让程序员脑袋变秃的罪魁祸首之一!

都2022年了,一个还不知道Lottie动画的前端已经OUT啦!

在反复的拉扯“折磨”中,有一批程序员就在不停的思索,将动画的设计实现与使用进行物理分割,让专业的人做更专业的事儿!

  1. 产出某种物料:让对色彩、交互更专业的UI同学完成动画的设计、实现、优化,产出一种可供识别的物料;
  2. 以某种形式直接识别、使用物料:前端研发通过某种形式直接识别该物料,调用后页面直接渲染动画,无须再配置路径动画、描边动画等;

基于这样的思考与探索,​​Lottie​​动画应运而生!

二、Lottie介绍

Lottie是一款由airbnb开源的跨平台动画渲染库,支持​​Android​​, ​​iOS​​, ​​Web​​, ​​Windows​​平台。是专门用于解析从AE(Adobe After Effects)中通过​​Bodymovin​​插件导出的JSON文件,直接渲染动画。

Lottie官网的传送门在此​​点我你将见证神奇​

本文的重点在于如何使用导出的JSON文件,在AE中如何开发动画以及插件Bodymovin的使用欢迎查阅其他相关资料~

一图胜千言 ~ ​​代码片段​

该示例代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lottie</title>
<!-- 重点:引入Lottie JS 文件 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.9.4/lottie.min.js"></script>
<style>
#app {
width: 400px;
height: 400px;
}
</style>
</head>
<body>
<!-- 定义动画渲染的容器 -->
<div id="app"></div>
</body>

<script>
// loadAnimation 渲染动画
const lottieAnimationItem = lottie.loadAnimation({
// 选取一个容器,用于渲染动画
container: document.querySelector("#app"),
// 定义JSON文件路径
path: "https://assets10.lottiefiles.com/packages/lf20_l3qxn9jy.json",
// 是否循环播放
loop: true,
// 渲染的格式svg/canvas/html,svg性能更优,兼容性更好
renderer: "svg",
});
</script>
</html>

开发人员进行简单的配置,引入​​Lottie​​,加载相应的JSON文件,动画就实现了!简不简单,神不神奇!

专业的人做专业的事儿,后期即使UI设计MM又多动画做出了调整,做为开发的你唯一需要做的就是将文件替换一下即可!是不是又可以挽救几根头发了~

​Lottie Files​​是一个专门针对Lottie动画设计、分享的网站。你可以在这个网站上上传自己制作的lottie动画,也可以浏览其他设计师上传的lottie动画,也可以快速体验,方便而有趣。

三、Lottie常见属性和方法

loadAnimation参数配置

属性名

描述

container

渲染动画所需容器

renderer

动画渲染类型,svg/canvas/html

loop

是否循环播放,布尔值

autoplay

是否自动播放,布尔值

path

一个指定的JSON文件路径,注意这里会发起一个http请求json文件

animationData

JSON动画数据,与path属性不共存

TIPS: 当设置path属性的时候,并不是简单的一个相对路径或者是绝对路径引入,而是lottie会发送一个http请求,访问这个json文件。如果是在vue/react项目中要注意最终的打包访问路径。

考虑页面性能更优,建议使用svg渲染方式,通过path加载远程JSON文件,使用animationData会让json文件打包到JS中,

loadAnimation方法返回的对象

属性名

类型

描述

play

() => void

播放动画

pause

() => void

暂停动画

stop

() => void

停止动画

play

() => void

播放动画

setSpeed

(number) => void

设置播放速度

destroy

() => void

销毁动画

四、封装Lottie - React Hooks版

为了在项目中能够快速复用,将Lottie动画渲染简易封装成react组件​​Lottie​​。

安装依赖

# lottie-web是针对web渲染的库
yarn add lottie-web

Lottie组件封装:

import React, { useRef, useEffect, useMemo, forwardRef, useImperativeHandle, Ref } from 'react';
import lottie, { AnimationItem } from 'lottie-web';

// 渲染类型
type rendererType = 'svg' | 'canvas' | 'html';

// 常用属性
interface IProps {
// 是否循环播放
loop?: boolean;
// 渲染动画的类型
renderer?: rendererType;
// 是否自动播放
autoplay?: boolean;
// 动画渲染数据,与path互斥
animationData?: any;
// JSON文件路径,与animationData互斥
path?: string;
}

export default forwardRef((props: IProps, ref: Ref<any>) => {
// 设置props的默认值
const { loop = true, renderer = 'svg', path = '', animationData, autoplay = true } = props;

// 设置动画渲染的容器
const containerEle = useRef(null);
// 对外暴露的ref对象
const lottieAnimation = useRef(null);

// 指定想父级调用组件暴露的ref对象,方便元素控制当前动画的播放与暂停
useImperativeHandle(ref, () => ({
// 获取当前动画对象实例
getInstance: () => lottieAnimation.current,
// 播放,继续播放
play: () => {
lottieAnimation.current.play();
},
// 暂停动画
pause: () => {
lottieAnimation.current.pause();
},
// 停止动画,区别于暂停动画pause()
stop: () => {
lottieAnimation.current.stop();
}
}));



// 缓存动画的相关配置
const animationOptions = useMemo(() => {
const options: IProps = {
loop,
renderer,
autoplay
};

// 优先取animationData
if (animationData) {
options.animationData = animationData;
} else {
options.path = path;
}

return options;
}, [loop, renderer, path, animationData, autoplay]);

useEffect(() => {
if (!containerEle.current) {
return;
}

// 渲染动画
const lottieAnimationItem: AnimationItem = lottie.loadAnimation({
container: containerEle.current,
...animationOptions
});

// 将渲染后的动画示例对象赋值给lottieAnimation.current,对外暴露
lottieAnimation.current = lottieAnimationItem;

// 一定要注意这里的对象销毁,避免内存泄露,以及重复渲染动画
return () => {
// 重置为null
lottieAnimation.current = null;
// 销毁动画对象
lottieAnimationItem.destroy();
};
}, [animationOptions]);

// 因为lottie动画是无线宽高的,所以这里直接设置渲染的容器宽度、高度为父级元素100%即可
return <div ref={containerEle} style={{ width: '100%', height: '100%' }}></div>;
});

五、Lottie组件的引入与调用

  1. 指定path或animationData
import React, { useRef } from "react";
import "./styles.css";
import Lottie from "./lottie";
import animationData from "./animation.json";

export default function App() {
// 初始化ref
const lottieRef = useRef(null);

return (
<div className="App">
{/* 指定路径 */}
<div className="container">
<button
onClick={() => {
if (!lottieRef.current) {
return;
}
// 暂停动画
lottieRef.current.pause();
}}
>
暂停
</button>
<button
onClick={() => {
if (!lottieRef.current) {
return;
}
// 从当前状态继续向前播放
lottieRef.current.play();
}}
>
播放
</button>
<button
onClick={() => {
if (!lottieRef.current) {
return;
}
// 停止动画,恢复到初始状态,注意与pause()方法的区别
lottieRef.current.stop();
}}
>
停止
</button>
<Lottie ref={lottieRef} path="https://assets10.lottiefiles.com/packages/lf20_l3qxn9jy.json"></Lottie>
</div>
{/* 指定animationData */}
<div className="container">
<Lottie animationData={animationData}></Lottie>
</div>
</div>
);
}

codesandbox地址:​​https://codesandbox.io/s/funny-resonance-dlpitg​

效果图:

都2022年了,一个还不知道Lottie动画的前端已经OUT啦!

结语

发表评论

相关文章