点赞 + 关注 + 收藏 = 学会了
本文简介
有时候在网页上看到一些很炫酷的小动画,比如loading特效,还能控制这个动画的状态,真的觉得很神奇。
大部分做后端的不想碰前端,做前端的不想碰动画特效。
其实啊,很多时候不需要自己写炫酷的特效,会调用第三方库已经挺厉害的了。比如今天要介绍的 Lottie。
Lottie 是什么?
🔗Lottie官网 airbnb.io/lottie/
Lottie 是一个适用于 Android、iOS、Web 和 Windows 的库,它可以解析使用 Bodymovin 导出为 JSON 的 Adobe After Effects 动画,并在移动设备和 Web 上本地渲染它们!
After Effects 是什么?Bodymovin 又是什么?
别怕,这些我也不会。作为前端,我会拿别人做好的东西来用😁
简单来说,Lottie 是 Airbnb 开发的动画库,特别适合前端开发人员。它可以轻松实现复杂的动画效果,不需要手写大量代码,只需引入现成的 JSON 文件即可。
今天不讲iOS,不讲Android,只讲如何在前端使用 Lottie。
安装 Lottie Web
要在前端项目中使用 Lottie,要么用 CDN 的方式引入,要么通过 NPM 下载。
CDN
在这个网址可以找到 Lottie 的各个版本的JS文件: cdnjs.com/libraries/b...
我使用的是 5.12.2 这个版本
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#lottie {
width: 200px;
height: 200px;
}
</style>
</head>
<body>
<div id="lottie"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.12.2/lottie.min.js"></script>
<script>
var animation = lottie.loadAnimation({
container: document.getElementById('lottie'), // 渲染动画的容器
renderer: 'svg', // 渲染方式
loop: true, // 是否循环
autoplay: true, // 是否自动播放
path: './Animation_1.json' // 动画 JSON 文件的路径
});
</script>
</body>
</html>
Animation_1.json
是我下载的一个动画文件,这个文件我放在同级目录里。这个动画文件在哪可以下载我接下来会介绍。这里先了解一下 CDN 的方式怎么引入 Lottie 即可。
NPM
用下面这个命令将 Lottie 下载到你的项目里。
npm install lottie-web
动画资源下载
前面介绍到,动画是用 AE 做好,然后用 Bodymovin 插件将动画转换成一个 JSON 文件,前端就可以使用 lottie-web 将这个 JSON 文件的内容转换成图像渲染到浏览器页面上。
如果想要现成的动画资源可以在这些地方找找
- lottiefiles :lottiefiles.com/
- iconfont的lottie模块 :www.iconfont.cn/lotties/ind...
- Creattie :creattie.com/
- Lottielab(自己编辑、下载) :www.lottielab.com/
我这里也给大家准备了一个动画文件,大家可以拿它来练手。
- 【百度网盘】链接: pan.baidu.com/s/1Qnp3BAAT... 提取码: d7gt
- 【阿里云盘】链接:www.alipan.com/s/sfMVak2Xh... 提取码:35kw
实现第一个 Lottie 动画
我通过 React
脚手架创建了一个 React
项目来举例说明如何使用 Lottie,在 Vue
里的用法也是一样的。
react
import React, { useEffect, useRef } from 'react';
import lottie from 'lottie-web';
import animationData from './assets/animations/Animation.json';
function App() {
const containerRef = useRef(null);
useEffect(() => {
const anim = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop: true,
autoplay: true,
animationData: animationData
});
}, []);
return <div ref={containerRef} style={{width: "300px", height: "300px"}}></div>;
}
export default App;
在 HTML 文件中,创建一个容器,用于放置 Lottie 动画。在这个例子中我创建了一个宽和高都是 300px
的 div
元素。
然后引入 lottie-web
以及放在前端项目里的 Animation.json
动画文件。
最后调用 lottie.loadAnimation()
来启动动画。它将一个对象作为唯一参数。
container
:动画容器,这个例子通过React
提供的语法获取到DOM
元素。renderer
:渲染方式,可选svg
、canvas
和html
。loop
:是否循环播放。autoplay
:是否自动播放。animationData
:本地的动画数据的对象。
这里需要注意,animationData
接收的动画对象是存放在前端项目的 JSON
文件,如果你的动画文件是存在别的服务器,需要通过一个 URL
引入的话就不能用 animationData
来接收了,而是要改成 path
。
js
const anim = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop: true,
autoplay: true,
path: 'https://lottie.host/68bd36a3-b21d-4909-9b61-9be6b0947943/gInO8owFG1.json'
});
Lottie 常用功能
播放、暂停、停止
控制动画的播放、暂停、停止是很常用的功能。
- 播放 :使用
play()
方法。顾名思义就是让动画动起来。 - 暂停 :使用
pause()
方法。暂停可以让动画在当前帧停下来。可以这么理解,你在看视频一个10秒的短视频,播放到第7秒的时候你按了"暂停",画面就停在第7秒的地方了。 - 停止 :使用
stop()
方法。停止和暂停都是让动画停下来,而停止会让动画返回第1帧画面的地方停下来。
react
import lottie from 'lottie-web';
import React, { useEffect, useRef } from 'react';
import animationData from './assets/animations/Animation.json';
function App() {
const containerRef = useRef(null);
let anim = null
useEffect(() => {
anim = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop: true,
autoplay: true,
animationData: animationData,
});
}, []);
// 播放动画
function play() {
anim.play()
}
// 暂停动画
function pause() {
anim.pause()
}
// 停止动画
function stop() {
anim.stop()
}
return <>
<div ref={containerRef} style={{width: "300px", height: "300px"}}></div>
<button onClick={play}>播放</button>
<button onClick={pause}>暂停</button>
<button onClick={stop}>停止</button>
</>;
}
export default App;
代码放这,建议自己运行起来体验一下。
设置动画播放速度
使用 setSpeed()
方法可以设置动画的播放速度,传入一个数字即可。默认的播放速度是1。
js
// 省略部分代码
// 2倍速度播放
anim.setSpeed(2)
这个参数支持正数(包括非整数)、0、负数。
- 大于1的正数:比默认速度快
- 大于0小于1:比默认速度慢
- 0:画面停止在第一帧不动了
- 小于0大于-1:动画倒放,而且速度比默认值慢
- -1:动画倒放,速度和默认值一样
- 小于-1:动画倒放,速度比默认值快
设置动画播放方向
这里说的播放方向指的是「正着放」还是「倒着放」。前面用 setSpeed()
方法可以做到这点。但还有一个叫 setDirection()
的方法也能做到。
setDirection()
接收一个数字参数,这个参数大于等于0时是正着播放,负数时是倒着播放。通常情况下,想倒着播放会传入 -1。
js
// 省略部分代码
anim.setDirection(-1)
看,面是吐出来的。
设置动画进度
通过 goToAndStop()
方法可以控制动画跳转到指定帧或时间并停止。
goToAndStop(value, isFrame)
接收2个参数。
value
:数值,表示要跳转到的帧数或时间点。isFrame
:布尔值,默认为false
。如果设置为true
,则value
参数表示帧数;如果设置为false
,则value
参数表示时间(以毫秒为单位)。
js
function goToAndStop() {
anim.goToAndStop(1000, false)
}
return <>
<div ref={containerRef} style={{width: "300px", height: "300px"}}></div>
<button onClick={goToAndStop}>跳转到1秒</button>
</>;
如果 goToAndStop
第二个参数为 true
则表示要跳转到指定帧数,这个值不能超过动画的总帧数。
销毁动画实例
有些场景在某个时刻需要将动画元素删除掉,比如在数据加载时需要显示 loading,数据加载成功或者失败后需要隐藏 loading,此时可以用 destroy
将 Lottie 动画实例销毁掉。
javascript
// 省略部分代码
anim.destroy()
动画监听事件
动画有很多个状态,比如动画数据加载完成/失败、动画播放结束、循环下一次播放、进入新的一帧。Lottie 为我们提供了几个常用的监听方法。
而要监听这些事件,需要在 lottie
实例上用 addEventListener
方法绑定各个事件。
动画数据加载情况
监听动画数据(JSON文件)加载成功或者失败,可以用这两个方法。
data_ready
:数据加载成功后执行。data_failed
:数据加载失败后执行。
需要注意,这两个方法只适用 path
的方式加载数据时触发。animationData
加载的是本地数据,并不会触发这两个方法。
js
// 省略部分代码
let anim = null;
useEffect(() => {
anim = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop: true,
autoplay: true,
path: 'https://lottie.host/68bd36a3-b21d-4909-9b61-9be6b0947943/gInO8owFG1.json'
});
anim.addEventListener('data_ready', () => {
console.log('数据加载完成');
});
anim.addEventListener('data_failed', () => {
console.log('数据加载失败');
})
}, []);
初始配置完成后
在数据加载前,还可以通过 config_ready
监听初始化配置的完成情况。
要让 config_ready
生效,同样需要通过 path
的方式加载数据。
config_ready
的执行顺序排在 data_ready
之前。
js
// 省略部分代码
let anim = null;
useEffect(() => {
anim = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop: true,
autoplay: true,
path: 'https://lottie.host/68bd36a3-b21d-4909-9b61-9be6b0947943/gInO8owFG1.json'
});
anim.addEventListener('data_ready', () => {
console.log('数据加载完成');
});
anim.addEventListener('config_ready', () => {
console.log('初始化成功');
});
}, []);
动画播放结束
当动画播放结束时,会触发 complete
事件。
如果 loop
为 true
的话时不会触发 complete
的,因为一直循环的话动画是没有结束的那天。
js
// 省略部分代码
let anim = null;
useEffect(() => {
anim = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop: false,
autoplay: true,
animationData: animationData,
});
anim.addEventListener('complete', () => {
console.log('动画播完了');
});
}, []);
动画循环播放结束
当 loop
为 true
时,每循环播放完一次就会触发 loopComplete
事件。
js
// 省略部分代码
let anim = null;
useEffect(() => {
anim = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop: true,
autoplay: true,
animationData: animationData,
});
anim.addEventListener('loopComplete', () => {
console.log('循环结束,准备进入下一次循环');
});
}, []);
当你通过 pause()
暂停了动画,过一阵用 play()
继续播放,也会等这次动画完整播放完才会触发 loopComplete
。
进入新的一帧
一个动画由很多个画面组成,每个画面都属于1帧。动画每进入一帧时都会触发 enterFrame
事件。
js
// 省略部分代码
let anim = null;
useEffect(() => {
anim = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop: true,
autoplay: true,
animationData: animationData,
// path: 'https://lottie.host/68bd36a3-b21d-4909-9b61-9be6b0947943/gInO8owFG1.json'
});
anim.addEventListener('enterFrame', () => {
console.log('进入新帧');
});
}, []);
自己手写一个动画JSON?
手写 Lottie 的 JSON 动画文件相对复杂,因为需要对 Lottie 的 JSON 结构有较深入的理解。Lottie 的 JSON 文件基于 Bodymovin 插件输出的格式,主要包含静态资源、图层、形状以及帧动画信息。
由于相对复杂,所以不建议真的自己手写,这会显得你很傻。
Lottie JSON 文件由多个部分组成,主要包括:
assets
:动画中使用的资源(图片等)。layers
:动画中的每一层(类似于 Photoshop 图层)。shapes
:定义图形、路径等基本元素及其动画。animations
:定义每一帧的动画数据,包括位置、缩放、透明度等。
太复杂的元素我确实手写不出来,只能写一个简单的圆形从左向右移动演示一下。
json
{
"v": "5.6.10", // Lottie 版本
"fr": 30, // 帧率 (Frames per second)
"ip": 0, // 动画开始帧 (In Point)
"op": 60, // 动画结束帧 (Out Point)
"w": 500, // 画布宽度
"h": 500, // 画布高度
"nm": "circle animation",// 动画名称
"ddd": 0, // 是否是 3D 动画
"assets": [], // 静态资源(如图片等)
"layers": [ // 动画的图层
{
"ddd": 0, // 图层是否是 3D
"ind": 1, // 图层索引
"ty": 4, // 图层类型,4 代表形状图层
"nm": "circle", // 图层名称
"sr": 1, // 图层的播放速度
"ks": { // 图层的关键帧属性(动画数据)
"o": { // 不透明度动画
"a": 0, // 不透明度动画为 0,表示不设置动画
"k": 100 // 不透明度固定为 100%
},
"r": { // 旋转动画
"a": 0, // 不设置动画
"k": 0 // 旋转角度为 0
},
"p": { // 位置动画 (Position)
"a": 1, // a 为 1 表示位置有动画
"k": [
{
"i": { "x": 0.667, "y": 1 }, // 起始位置插值
"o": { "x": 0.333, "y": 0 }, // 终止位置插值
"n": "0p667_1_0p333_0", // 插值模式名称
"t": 0, // 起始帧
"s": [50, 250, 0], // 起始位置 (x: 50, y: 250)
"e": [450, 250, 0], // 结束位置 (x: 450, y: 250)
"to": [66.66667, 0, 0], // 起始插值控制点
"ti": [-66.66667, 0, 0] // 终止插值控制点
},
{ "t": 60 } // 在 60 帧时结束动画
]
},
"a": { // 锚点动画(用于旋转或缩放中心)
"a": 0,
"k": [0, 0, 0] // 锚点固定在 (0, 0)
},
"s": { // 缩放动画 (Scale)
"a": 0,
"k": [100, 100, 100] // 保持 100% 缩放
}
},
"ao": 0, // 自动定向
"shapes": [ // 图形数组,定义图层中的形状
{
"ty": "el", // 图形类型 'el' 代表 ellipse(椭圆/圆形)
"p": { // 椭圆的中心点
"a": 0,
"k": [0, 0]
},
"s": { // 椭圆的大小
"a": 0,
"k": [100, 100] // 圆的宽和高为 100px
},
"nm": "ellipse"
},
{
"ty": "st", // 图形类型 'st' 代表 stroke(描边)
"c": { // 描边颜色
"a": 0,
"k": [1, 0, 0, 1] // 红色 [R: 1, G: 0, B: 0, Alpha: 1]
},
"o": { // 描边不透明度
"a": 0,
"k": 100
},
"w": { // 描边宽度
"a": 0,
"k": 10
},
"lc": 1, // 线帽样式
"lj": 1, // 线接样式
"ml": 4 // 折线限制
}
],
"ip": 0, // 图层开始帧
"op": 60, // 图层结束帧
"st": 0, // 图层起始时间
"bm": 0 // 混合模式
}
]
}
-
v
: 表示 Lottie 动画的版本。 -
fr
: 帧率,表示每秒多少帧。在这个示例中,每秒播放 30 帧。 -
ip
和op
: 分别代表动画的起始帧和结束帧。本例中,动画从第 0 帧开始,到第 60 帧结束。 -
layers
: 图层数组。每个图层包含ks
(关键帧属性),用于控制位置、缩放、旋转等动画参数。ty: 4
: 图层类型为形状图层。p
: 定义了位置动画,从帧 0 开始,圆形从 (50, 250) 移动到 (450, 250) 的位置,表示从画布左侧移动到右侧。
-
shapes
: 定义了图形的属性。-
el
: 表示一个椭圆形,即我们定义的圆形。 -
st
: 表示圆形的描边,颜色为红色,宽度为 10px。
-
以上就是本文的全部内容,如果本文对你有帮助,欢迎转发给你的朋友。
点赞 + 关注 + 收藏 = 学会了