在我们大大小小的项目里,基本上gif、png序列帧、svg动画占据了比较大的一部分,很多情况下我们都忽略了他们本身的一部分缺点。因此对于如何让动画有一个新的实现方式有了兴趣,lottie便步入我的视野。

GiF、PNG、SVG动画

Gif :

  • 优点:Gif 广泛支持 Internet 标准。支持无损耗压缩和透明度。
  • 缺点:Gif 文件一般较大,大小固定,无法缩放以匹配大屏幕和高密度屏幕,容易有锯齿,不能控制,只支持 256 色调色板,对动画画质要求高则无法满足,也不能交互,会引起重绘。

Png :

优点:写法简单,可以使用css动画,js去操作,实现周期短,出图快。
缺点:若是合成雪碧图,会产生文件大,且在不同屏幕分辨率下可能会失真的问题,若是动态替换src地址,则会触发多次资源请求,浪费更大。

Svg :

优点:矢量图形,不受像素影响
缺点:实现成本高,容易出现动画还原度低的情况

lottie

1、介绍

Lottie是 airbnb 开源的可应用于Android,iOS,Web,React Native和Windows动画库, 本质上是一套跨平台的动画解决方案。它提供了一套完整的从 AE 到各个终端的工具流,通过 AE 的 Bodymovin 插件将设计师做的动画导出成一套定义好的 json 文件,之后再通过 Lottie 各端的库就可以实现动画效果。

2、lottie-web

ps:作为一个前段开发,在此先介绍下lottie-web

1、安装

npm install lottie-web

2、调用

import lottie from 'lottie-web';

const dataJson = require('data.json');

let animation = lottie.loadAnimation({
    container: Ele,
    renderer: 'svg',
    loop: true,
    autoplay: true,
    animationData: dataJson,
    assetsPath: url,
});

3、属性

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(); // 删除该动画,移除相应的元素标签等。在unmount的时候,需要调用该方法

4、事件

* data_ready:数据准备完成
* complete: 播放完成(循环播放下不会触发)
* loopComplete: 当前循环下播放(循环播放/非循环播放)结束时触发
* enterFrame: 每进入一帧就会触发,播放时每一帧都会触发一次,stop方法也会触发
* segmentStart: 播放指定片段时触发,playSegments、resetSegments等方法刚开始播放指定片段时会发出,如果playSegments播放多个片段,多个片段最开始都会触发。
* data_ready: 动画json文件加载完毕触发
* DOMLoaded: 动画相关的dom已经被添加到html后触发
* destroy: 将在动画删除时触发

5、注意

  • 描边动效不支持,会导致性能问题,web不支持
  • 图层越多,json数据越大
  • 导出的图层以#svgId命名,可以通过Id获取;导出以.svgClass命名,可以通过Class获取

3、封装lottie-web组件,在Vue或React使用

Vue

<.template>
    <.div :style="styles" ref="lottieEl"><./div>
<./template>


import lottie from 'lottie-web'
export default {
    props: {
      options: {
        type: Object,
        required: true
      },
      styles:{
        type:Object,
        default:()=>{
          return {
            width: '80px',
            height: '80px', 
          }
        }
      },
      json:{
        type: Object,
        required: true
      }
    },
    data() {
      return {
        lottie:{},
      }
    },
    mounted() {
      this.lottie = lottie.loadAnimation({ 
        container: this.$refs.lottieEl,
        renderer: 'svg',
        loop: this.options.loop ? true : false,
        autoplay: this.options.autoplay ? true : false,
        animationData: this.json,
      })
    }
  }
<./script>

React

import React from 'react'
import Lottie from 'react-lottie';
import * as jsonData from './data.json'
export default class LottieWrapper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isStopped: false, isPaused: false};
  }
  render() {
    const buttonStyle = {
      display: 'block',
      margin: '10px auto'
    };
    const defaultOptions = {
      loop: true,
      autoplay: true,
      animationData: jsonData,
    };
    return <.div>
      <.Lottie options={defaultOptions}
        height={400}
        width={400}
        isStopped={this.state.isStopped}
        isPaused={this.state.isPaused}
      />
      <.button style={buttonStyle} onClick={() => this.setState({isStopped: true})}>stop
      <.button style={buttonStyle} onClick={() => this.setState({isStopped: false})}>play
      <.button style={buttonStyle} onClick={() => this.setState({isPaused: !this.state.isPaused})}>pause
    <./div>
  }
}

附录:lottie-web官方文档

ps:由于编辑器插件Bug会渲染标签,运行时请去除标签前面的点号

Tokials

月亮被嚼碎了变成星星,你就藏在漫天的星光里。

Tokials

月亮被嚼碎了变成星星,你就藏在漫天的星光里。