如何在vue中使用Lottie

12,621 阅读5分钟

这是我参与新手入门的第三篇文章

前言

我之前写了一篇文章前端人需要了解的JsDoc,应留言的同学,本来是想接着把JsDoc的内容补充的更完善一些的. 但是写了一些,感觉后边补的一些内容写的枯燥且无聊,写的就很像是文档,后面想了一下,同学还是自己去找一下JsDoc的文档了解一下,更妥当一点。 今天我们还是了解一下Lottie这个比较有趣的动画库吧.

Lottie简介

官方介绍:Lottie是一个库,可以解析使用AE制作的动画(需要用bodymovie导出为json格式),支持web、ios、android、flutter和react native。 在web端,lottie-web库可以解析导出的动画json文件,并将其以svg或者canvas的方式将动画绘制在我们的页面上.

Lottie的优点

  1. 动画由设计使用专业的动画制作工具AE来实现,使动画实现更加方便,且效果更好
  2. 前端可以方便的调用动画,并对动画进行控制,减少前端动画工作量
  3. 设计制作动画,前端展现动画,分工明确
  4. 使用lottie方案,json文件大小比gif文件小很多,性能也会更好

lottie-web 在前端的使用

  1. 安装lottie-web
npm install lottie-web
  1. lottie-web的基本用法
const animation = lottie.loadAnimation({
  container: document.getElementById('domId'), // 绑定dom节点
  renderer: 'svg', // 渲染方式:svg、canvas
  loop: true, // 是否循环播放,默认:false
  autoplay: true, // 是否自动播放, 默认true
  animationData: // AE动画使用bodymovie导出为json数据
})
  1. lottie-web 常用方法 前面我们就初始化了一个lottie对象了. 然后我们介绍它的一些常用方法
animation.play(); // 播放,从当前帧开始播放

animation.stop(); // 停止,并回到第0帧

animation.pause(); // 暂停,并保持当前帧

animation.goToAndStop(value, isFrame); // 跳到某个时刻/帧并停止isFrame(默认false)指示value表示帧还是时间(毫秒)

animation.goToAndPlay(value, isFrame); // 跳到某个时刻/帧并进行播放

animation.goToAndStop(30, true); // 跳转到第30帧并停止

animation.goToAndPlay(300); // 跳转到第300毫秒并播放

animation.playSegments(arr, forceFlag); // arr可以包含两个数字或者两个数字组成的数组,forceFlag表示是否立即强制播放该片段

animation.playSegments([10,20], false); // 播放完之前的片段,播放10-20帧

animation.playSegments([[0,5],[10,18]], true); // 直接播放0-5帧和10-18帧

animation.setSpeed(speed); // 设置播放速度,speed为1表示正常速度

animation.setDirection(direction); // 设置播放方向,1表示正向播放,-1表示反向播放

animation.destroy(); // 删除该动画,移除相应的元素标签等。

Lottie-web 常用的事件

animation.addEventListener('data_ready', () => {}) // 动画数据加载完毕
animation.addEventListener('config_ready', () => {}) // 完成初始配置后
animation.addEventListener('data_failed', () => {}) // 加载动画数据失败
animation.addEventListener('loaded_images', () => {}) // 所有图片加载成功或者失败
animation.addEventListener('DOMLoaded', () => {}) // 将元素添加到DOM后

Lottie的免费资源

之前我们说过Lottie的动画是通过AE制作好了动画后,再使用bodymovie导出为json格式。其实有一个网站,它提供了一些免费的动画(当然也有付费的)直接有我们需要的动画json数据.

image.png

如下面的动图, 我们找到我们想要的动画,然后点击后,弹出窗口,点击下载,格式为JSON。然后就能把这个动画的json数据用到我们自己的项目里边去了. QQ20210711-211633-HD.gif

好了介绍完了它的用法后,我们现在就去vue中去做一个实战

在vue中使用lottie

  1. 使用vite跑vue
npm init @vitejs/app <project-name>
  1. 安装lottie-web
npm install lottie-web
  1. 封装一个基础的组件lottie.vue, 主要就是初始化好lottie对象,然后把对象传递出去给其他组件用
<template>
  <div :style="style" ref="lavContainer"></div>
</template>

<script>
import lottie from 'lottie-web'

export default {
  name: 'lottie',
  props: {
    options: {
      type: Object,
      required: true,
    },
    height: Number,
    width: Number,
  },

  computed: {
    style() {
      return {
        width: this.width ? `${this.width}px` : '100%',
        height: this.height ? `${this.height}px` : '100%',
      }
    },
  },

  mounted() {
    this.anim = lottie.loadAnimation({
      container: this.$refs.lavContainer,
      renderer: 'svg',
      loop: this.options.loop !== false,
      autoplay: this.options.autoplay !== false,
      animationData: this.options.animationData,
    })
    this.$emit('animCreated', this.anim)
  },
  
  unmounted () {
    this.anim && this.anim.destroy()
  }
}
</script>

  1. 基于上面的组件,我们封装一个更具象一点的组件clickIcon,这个组件也是通用组件,增加了点击后,动画交互需要怎么走向等逻辑.
<template>
  <div class="clickIcon">
    <div
      class="iconBox"
      :style="{ width: width + 'px', height: height + 'px' }"
    >
      <slot name="svg" v-bind:data="{ toggle, flag, iconWidth, iconHeight }"></slot>
      <lottie
        @click="toggle"
        :class="{ show: flag === true || !defaultSlot }"
        class="like"
        style="display: none;"
        :options="options"
        :height="height"
        :width="width"
        v-on:animCreated="handleAnimation"
      />
    </div>
  </div>
</template>

<script>
import { computed, ref, defineComponent } from "vue";
import Lottie from "./lottie.vue";
let anim = null
/**
 * 点击icon然后播放一段动画的组件
 * 适合收藏、点赞等小功能
 */

export default defineComponent({
  name: "clickIcon",
  props: {
    // 宽度
    width: {
      type: Number,
      default: 100,
    },
    // 高度
    height: {
      type: Number,
      default: 100,
    },
    // 初始化Lottie需要的参数
    options: {
      type: Object,
      default: () => {},
    },
    // 是否需要一个插槽,显示一个默认的图标
    defaultSlot: {
      type: Boolean,
      default: true
    },
    // 从外面传递的一个点击后需要的交互效果
    toggleFun: {
      type: Function,
      default: null
    }
  },
  components: {
    lottie: Lottie,
  },
  emits: ['init'],
  setup(props, { emit }) {
    // 动画速度
    const animationSpeed = 2
    // 点击交互标识
    let flag = ref(false);
    // 图标高度
    const iconWidth = computed(() => {
      return props.width;
    });
    // 图标宽度
    const iconHeight = computed(() => {
      return props.height;
    });
    // 点击图标交互
    const toggle = function() {
      if (!props.defaultSlot) {
        props.toggleFun && props.toggleFun(anim)
      } else {
        flag.value = !flag.value;
        if (flag.value) {
          anim.play();
        } else {
          anim.stop();
        }
      }
    };
  // 获取anim对象
    const handleAnimation = function(animated) {
      anim = animated;
      onSpeedChange()
      emit('init', animated)
    }
    // 停止动画
    const stop = function() {
      anim.stop();
    }
    // 播放动画
    const play = function() {
      anim.play();
    }
    // 暂停动画
    const pause = function() {
      anim.pause();
    }
    // 控制播放速度
    const onSpeedChange = function() {
      anim.setSpeed(animationSpeed);
    }
    return {
      iconWidth,
      iconHeight,
      handleAnimation,
      flag,
      toggle,
      stop,
      play,
      pause
    };
  },
});
</script>

<style scoped>
.iconBox {
  position: relative;
}
.show {
  display: inline-block !important;
}
.hidden {
  display: none !important;
}
.like {
  cursor: pointer;
}
.icon {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
</style>

接下来我们就写一个喜欢组件like.vue,如之前我们看到的效果 QQ20210711-211633-HD.gif 先把下载的动画json文件,放到资源文件目录,然后我们再用代码调用它使用.

<template>
  <lottie
    class="like"
    :options="defaultOptions"
    :height="height"
    :defaultSlot="false"
    :width="width"
    @init="init"
    :toggleFun="toggle"
    ref="lottie"
  >
  </lottie>
</template>

<script>
import Lottie from "../common/clickIcon.vue";
import animationData from "/public/like.json";

export default {
  name: "app",
  components: {
    lottie: Lottie,
  },
  props: {
    width: {
      type: Number,
      default: 60,
    },
    height: {
      type: Number,
      default: 60,
    },
  },
  methods: {
    init (animation) {
      animation && animation.goToAndStop(0, true)
    },
    toggle (animation) {
      if (this.toggleFlag) {
        animation.playSegments([50, 90], true); // 从50帧播放到最后
      } else {
        animation && animation.playSegments([0, 50], true); // 从第0帧播放到50帧
      }
      this.toggleFlag = !this.toggleFlag
    }
  },
  data() {
    return {
      toggleFlag: false,
      defaultOptions: {
        name: "like",
        animationData: animationData,
        autoplay: false,
        loop: false,
      }
    };
  }
};
</script>

<style scoped>
.hidden {
  display: none;
}
</style>

上边的效果之所以这样做,是因为我们下载的‘喜欢’动画的json文件,它是由两个状态组成的, 0-50帧是由未选中到选中状态的动画,50->90帧是选中状态->未选中状态的动画. 具体多少帧到多少帧可以从网站下载json文件那个窗口下面的进度去看到的.

  1. 使用喜欢组件
<template>
  <div id="app">
    <like></like>
  </div>
</template>

<script>
import { defineComponent } from "vue";
import like from "./components/like/index.vue";

export default defineComponent({
  components: {
    like,
  },
});

具体效果如下

QQ20210711-214951-HD.gif

结语

以上就是利用Lottie在vue中实现一个喜欢组件了。 其实目前只是写了这么一个demo而已,大家有兴趣的话,可以把它再实现完一下,现在组件还没有去记录一下组件的默认状态, 它可能默认就是被选中的状态. 另外我们这一次拿到的动画组件刚好是有选中和未选中两种状态的,在之前给大家介绍的免费下载动画json文件的网站里边还有一些动画是只给到一个选中的动画效果,并没有未选中的状态,这时候我们可以自己去找一个类似的svg图标,然后作为默认的图标,点击后,触发选中的动画效果. 这种场景碰到的极少,如果是公司项目的话,可以要求美工去做两个状态的动画效果,如果是自己的个人项目,然后碰到了很喜欢的免费动画,然而它只提供了一个状态的话,这时候才有用。 我在组件其实也把这种情况考虑进去了,就是defaultSlot把这个属性设置成true, 然后在写组件的时候,添加一个插槽作为一个默认组件.

写在最后

大家可以给个点赞鼓励一下萌新嘛? 哈哈哈, 先谢过了~