乐趣区

关于前端:🌟前端使用Lottie实现炫酷的开关效果🌟

前言

公众号:【可乐前端】,期待关注交换,分享一些有意思的前端常识

在平时的开发过程中,前端或多或少都会遇到实现动画成果的场景。手写动画是一件相当麻烦的事件,调来调去不仅费时费力,可能还会被产品 /UI 吐槽:这动画成果也不难呀,为什么就不能实现呢?/ 为什么就没有还原成我想要的样子呢。

比如说产品让咱们实现这样的一个开关动效

明天咱们就用动画的实现形式——Lottie,来百分百还原设计师的动画成果,并且能够大大提高咱们的工作效率(摸鱼工夫)。

Lottie简介

首先咱们先来看一下,平时咱们实现动画都有哪些形式,它们别离有什么优缺点:

动画类型 长处 毛病
CSS 动画 应用简便,通过 @keyframestransition创立动画;浏览器原生反对,性能较好 管制无限,不适用于简单动画;简单动画可能须要大量 CSS 代码,简短
JavaScript 动画 提供更高水平的管制和灵活性;实用于简单和精密动画成果 引入库减少页面累赘,可能须要学习曲线;使用不当容器对页面性能造成影响,产生卡顿
GIF 动画 制作和应用简略,无需额定代码;简直所有浏览器原生反对 无限色彩深度,不适用于所有场景;清晰度与文件尺寸成正比,无奈适应所有分辨率
Lottie 反对矢量动画,放弃清晰度和流畅性;跨平台应用,实用于 iOS、Android 和 Web 在一些较旧或性能较低的设施上,播放较大的 Lottie 动画可能会导致性能问题;对设计师要求较高

Lottie是由 Airbnb 开发的一个开源库,用于在挪动端和 Web 上出现矢量动画。它基于 JSON 格局的 Bodymovin 文件,能够将由设计师在 AE 中创立的动画导出为可在 Lottie 库中播放的文件。

绝对于手写 CSS/JS 动画而言,它能够大大减少前端开发的工作量,绝对于 GIF 文件来说,它能够在一个正当的文件体积内保障动画的清晰度以及晦涩水平。上面咱们就介绍一下如何播放一个 Lottie 动画,并实现一个炫酷的开关成果。

Hello Lottie

假如咱们当初曾经有一个 Lottiejson文件,那么当初装置一些依赖

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:是否自动播放
  • animationDataLottie动画 json 资源
  • rendererSettings.preserveAspectRatio:指定如何在给定容器中渲染 Lottie 动画

    • xMidYMid: 示意在程度和垂直方向上都在核心对齐
    • 示意放弃纵横比,但可能会裁剪超出容器的局部

正 / 反向播放

失常的把 Lottie 动画播放进去之后,咱们就能够开始实现一个开关的性能。其实就是点击的时候更换 Lottie 的播放方向,这里对应的是 direction 字段,direction1 时正向播放,direction-1 时反向播放。

咱们就要实现上面的性能:

  • 点击时切换方向
  • 播放过程中加锁,禁止切换方向
  • 监听播放完结事件,解锁
  • loop改为 falseautoplay 改为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>
  );
};

这样咱们就是实现了一个开关的成果

继续时长

Lottiejson中,有几个要害的字段跟动画的播放时长有关系:

  • 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

如果你有一些别的想法,欢送评论区交换~如果你感觉有意思的话,点点关注点点赞吧~

退出移动版