前言
公众号:【可乐前端】,期待关注交换,分享一些有意思的前端常识
在平时的开发过程中,前端或多或少都会遇到实现动画成果的场景。手写动画是一件相当麻烦的事件,调来调去不仅费时费力,可能还会被产品 /UI 吐槽:这动画成果也不难呀,为什么就不能实现呢?/ 为什么就没有还原成我想要的样子呢。
比如说产品让咱们实现这样的一个开关动效
明天咱们就用动画的实现形式——Lottie
,来百分百还原设计师的动画成果,并且能够大大提高咱们的工作效率(摸鱼工夫)。
Lottie
简介
首先咱们先来看一下,平时咱们实现动画都有哪些形式,它们别离有什么优缺点:
动画类型 | 长处 | 毛病 |
---|---|---|
CSS 动画 | 应用简便,通过 @keyframes 和transition 创立动画;浏览器原生反对,性能较好 |
管制无限,不适用于简单动画;简单动画可能须要大量 CSS 代码,简短 |
JavaScript 动画 | 提供更高水平的管制和灵活性;实用于简单和精密动画成果 | 引入库减少页面累赘,可能须要学习曲线;使用不当容器对页面性能造成影响,产生卡顿 |
GIF 动画 | 制作和应用简略,无需额定代码;简直所有浏览器原生反对 | 无限色彩深度,不适用于所有场景;清晰度与文件尺寸成正比,无奈适应所有分辨率 |
Lottie | 反对矢量动画,放弃清晰度和流畅性;跨平台应用,实用于 iOS、Android 和 Web | 在一些较旧或性能较低的设施上,播放较大的 Lottie 动画可能会导致性能问题;对设计师要求较高 |
Lottie
是由 Airbnb
开发的一个开源库,用于在挪动端和 Web
上出现矢量动画。它基于 JSON
格局的 Bodymovin
文件,能够将由设计师在 AE 中创立的动画导出为可在 Lottie 库中播放的文件。
绝对于手写 CSS/JS
动画而言,它能够大大减少前端开发的工作量,绝对于 GIF
文件来说,它能够在一个正当的文件体积内保障动画的清晰度以及晦涩水平。上面咱们就介绍一下如何播放一个 Lottie
动画,并实现一个炫酷的开关成果。
Hello Lottie
假如咱们当初曾经有一个 Lottie
的json
文件,那么当初装置一些依赖
npm i react-lottie prop-types
装置完之后咱们就能够这样子来播放一个 Lottie
动画:
import animationData from "../../assets/switch-lottie.json";
const LottieSwitch = () => {const playing = useRef(false);
const options = {
loop: true,
autoplay: true,
animationData: animationData,
rendererSettings: {preserveAspectRatio: "xMidYMid slice",},
};
return (
<Lottie
options={options}
height={20}
width={40}
/>
);
};
来解释一下下面的 options
参数外面各个字段是什么意思:
loop
:是否循环播放autoplay
:是否自动播放animationData
:Lottie
动画json
资源-
rendererSettings.preserveAspectRatio
:指定如何在给定容器中渲染Lottie
动画xMidYMid
: 示意在程度和垂直方向上都在核心对齐- 示意放弃纵横比,但可能会裁剪超出容器的局部
正 / 反向播放
失常的把 Lottie
动画播放进去之后,咱们就能够开始实现一个开关的性能。其实就是点击的时候更换 Lottie
的播放方向,这里对应的是 direction
字段,direction
为 1
时正向播放,direction
为 -1
时反向播放。
咱们就要实现上面的性能:
- 点击时切换方向
- 播放过程中加锁,禁止切换方向
- 监听播放完结事件,解锁
loop
改为false
;autoplay
改为false
实现代码如下:
const LottieSwitch = () => {const [direction, setDirection] = useState(null);
const playing = useRef(false);
const options = {
loop: false,
autoplay: false,
animationData: animationData,
rendererSettings: {preserveAspectRatio: "xMidYMid slice",},
};
const handleClick = () => {if (playing.current) {return;}
playing.current = true;
setDirection((prevState) => (prevState === 1 ? -1 : 1));
};
return (<div style={{ padding: 40}}>
<div onClick={handleClick} className={styles.lottieWrapper}>
<Lottie
direction={direction}
options={options}
speed={2}
height={20}
width={40}
eventListeners={[
{
eventName: "complete",
callback: () => {playing.current = false;},
},
]}
/>
</div>
</div>
);
};
这样咱们就是实现了一个开关的成果
继续时长
在 Lottie
的json
中,有几个要害的字段跟动画的播放时长有关系:
fr
:帧率,每一秒的帧数ip
:开始帧op
:完结帧
如果说有上面的一个形容:
{
"fr": 30,
"ip": 0,
"op": 60,
}
则示意帧率是 30
帧,从第 0
帧开始,60
帧完结,那这个动画的继续时长是 (op-ip)/fr
,为 2s
。那如果咱们心愿整个动画的播放时长是500ms
,则只须要把Lottie
的倍速调整为 4
。对应的就是speed
字段:
<Lottie
direction={direction}
options={options}
speed={4}
height={20}
width={40}
eventListeners={[
{
eventName: "complete",
callback: () => {playing.current = false;},
},
]}
/>
批改 Lottie
在 Lottie json
中,形容整个动画的过程以及成果其实对应的就是某个值。在实现的过程中,其实开发是能够去批改这些值的。比如说咱们能够批改下面开关的边框色彩以及小球的色彩。
首先在页面中找到小球对应的色彩是rgb(99, 102, 241)
在 Lottie JSON
文件中,色彩信息通常呈现在示意图层款式的字段中。常见的字段是 "c"(color)
。"c"
字段示意色彩,通常以 RGBA
格局(红绿蓝透明度)存储。例如:
"c": {"a":0,"k":[1,0,0,1]}
这示意红色,RGBA
值为 [1, 0, 0, 1]
。
rgb(99, 102, 241)
转成下面的写法那就是 "c": {"a":0,"k":[99/255,102/255,241/255,1]}
。以99/255
为例,后果是 0.38823529411764707
,那么就拿这个后果去json
文件中找到对应的节点。
对应有 2
个后果,就是小球的色彩以及边框的色彩。当咱们找到这个值的时候,如果咱们想批改这个值,就必须晓得这个值的门路,在一个 Lottie
中,想肉眼找到这个值的门路是一件很难的事件。所以咱们写一个辅助函数:
const updateJsonValue = (json, targetValue, newValue) => {const find = (json, targetValue, currentPath = []) => {for (const key in json) {if (json[key] === targetValue) {return [...currentPath, key];
} else if (typeof json[key] === "object" && json[key] !== null) {const path = find(json[key], targetValue, [...currentPath, key]);
if (path) {return path;}
}
}
};
const res = JSON.parse(JSON.stringify(json));
const path = find(res, targetValue);
let current = res;
for (let i = 0; i < path.length - 1; i++) {const key = path[i];
current = current[key];
}
const lastKey = path[path.length - 1];
current[lastKey] = newValue;
return json;
};
下面的辅助函数就帮忙咱们找到这个值的门路,并批改目标值。比如说咱们想把目前的色彩改成绿色 (rgb(25, 195, 125)
),就能够找到对应的门路,并批改。别忘了替换的时候把rgb
对应的值除以255
。
let newAnimationData = updateJsonValue(animationData, 0.388235300779, 0.09803921568627451)
newAnimationData = updateJsonValue(newAnimationData, 0.388235300779, 0.09803921568627451)
newAnimationData = updateJsonValue(newAnimationData, 0.40000000596, 0.7647058823529411)
newAnimationData = updateJsonValue(newAnimationData, 0.40000000596, 0.7647058823529411)
newAnimationData = updateJsonValue(newAnimationData, 0.945098042488, 0.49019607843137253)
newAnimationData = updateJsonValue(newAnimationData, 0.945098042488, 0.49019607843137253)
把握了这种形式之后,咱们就能批改 Lottie
外面的大部分内容,包含文案、资源图片、色彩等等。
最初
以上就是一些 Lottie
的应用以及批改的介绍,下次再遇到比拟麻烦的动画需要。就能够跟产品说:能够做,让 UI
给我导出一个Lottie
。
如果你有一些别的想法,欢送评论区交换~如果你感觉有意思的话,点点关注点点赞吧~