在小程序中使用酷炫的Lottie动画,支持高版本json动画文件!

1,684 阅读2分钟

前言

lottie 动画库适配小程序的版本,该库基于官方库进一步封装,用法和官方一致。

能找到这篇文章想必大家已经知道lottie动画是什么,以及有什么优点,这里就不多说了。

因官方库已经800年不维护更新了,UI给的较新版本的lottie json 动画文件使用该库已无法正常显示,故做了以下升级:

  • 使用当前最新版本的 lottie 库,广泛支持更多版本的 lottie json 动画文件

    • 截止到2025年3月,最新版本为2.12.2
  • 精简项目,直接使用js文件,不再依赖lottie-web包,js文件从bodymovin libraries获取,想用哪个用哪个。

  • 使用Rollup打包,支持 esm 和 cjs 两种模块化方式

  • 内置Taro版本的组件,参考 examples/taro/LottieAnim

lottie 的相关介绍与动画生成方法等请参考官方说明

依赖小程序基础库版本 >= 2.8.0 的环境

选择库文件时,请选择 lottie_canvas.js 文件 或 lottie_canvas.min.js 文件,因为小程序使用canvas来绘制lottie动画

使用

可参考该代码片段:developers.weixin.qq.com/s/2TYvm9mJ7…。大致步骤如下:

  1. 通过 npm 安装:
npm install --save lottie-miniprogram-modern

2. 传入 canvas 对象用于适配

<canvas id="canvas" type="2d"></canvas>
import lottie from 'lottie-miniprogram-modern'

Page({
  onReady() {
    this.createSelectorQuery().select('#canvas').node(res => {
      const canvas = res.node
      lottie.setup(canvas)
    }).exec()
  }
})

3. 使用 lottie 接口

lottie.setup(canvas)
this.ani = lottie.loadAnimation({
  ...
})
this.ani.destroy() // 页面退出需销毁

在 Taro 中使用

/**
 * @description lottie动画组件
 */

import Taro from '@tarojs/taro';
import { Canvas } from '@tarojs/components';
import { useImperativeHandle, forwardRef, useRef, useEffect } from 'react';
import lottie from 'lottie-miniprogram';

export interface WxLottieRef {
  play: () => void;
  pause: () => void;
  stop: () => void;
  destroy: () => void;
}

interface Props {
  lottieId: string; // canvas id
  width: number; // 宽度
  height: number; // 高度
  animationData?: any; // 动画数据本地json
  path?: string; // 远程url
  loop?: boolean; // 是否循环
  autoplay?: boolean; // 是否自动播放
}

const LottieView = forwardRef<WxLottieRef, Props>((props, ref) => {
  const {
    lottieId = 'lottieCanvas',
    animationData,
    path,
    width,
    height,
    loop = true,
    autoplay = true,
  } = props;

  const lottieInstance = useRef<any>(null);
  const canvasRef = useRef(null);

  // 暴露组件方法
  useImperativeHandle(ref, () => ({
    play: () => lottieInstance.current?.play(),
    pause: () => lottieInstance.current?.pause(),
    stop: () => lottieInstance.current?.stop(),
    destroy: () => {
      lottieInstance.current?.destroy();
    },
  }));


  const loadAnimation = () => {
    if (!canvasRef.current) return;

    const query = Taro.createSelectorQuery();
    query.select(`#${lottieId}`)
      .fields({ node: true, size: true })
      .exec((res) => {
        const canvas = res[0].node;

        if (!canvas) {
          console.error('Canvas element not found');
          return;
        }

        const context = canvas.getContext('2d');
        const dpr = Taro.getSystemInfoSync().pixelRatio;
        canvas.width = width * dpr;
        canvas.height = height * dpr;
        context.scale(dpr, dpr);

        lottie.setup(canvas);

        // 如果已有动画实例,先销毁
        if (lottieInstance.current) {
          lottieInstance.current.destroy();
        }

        lottieInstance.current = lottie.loadAnimation({
          renderer: 'canvas',
          loop,
          autoplay,
          animationData,
          path,
          rendererSettings: {
            context,
            clearCanvas: true,
          },
        });
      });
  };

  // 监听path和animationData变化
  useEffect(() => {
    if (path || animationData) {
      loadAnimation();
    }
  }, [path, animationData]);

  useEffect(() => () => {
    // 组件卸载时清理动画实例
    if (lottieInstance.current) {
      lottieInstance.current.destroy();
    }
  }, []);

  return (
    <Canvas
      id={lottieId}
      type="2d"
      ref={canvasRef}
      style={{
        width: Taro.pxTransform(width * 2),
        height: Taro.pxTransform(height * 2),
      }}
    ></Canvas>
  );
});

export default LottieView;

// 引入组件
import LottieView from './LottieView';

// 使用组件
<LottieView lottieId="lottieCanvas" width={300} height={300} animationData={require('./animation.json')} />

接口

目前提供两个接口:

lottie.setup(canvas)

需要在任何 lottie 接口调用之前调用,传入 canvas 对象

lottie.loadAnimation(options)

与原来的 loadAnimation 有些不同,支持的参数有:

  • loop
  • autoplay
  • animationData
  • path (只支持网络地址)
  • rendererSettings.context (必填)

说明

  • 由于小程序本身不支持动态执行脚本,因此 lottie 的 expression 功能也是不支持的。
  • 感兴趣的小伙伴可看看该项目实现,实际上就是使用lottie提供的web脚本,在小程序中做一系列补丁后,以让它可以在小程序环境下使用,项目地址 github.com/Pursue-LLL/…