react-lottie动画组件封装

  1. 引入lottie.json即可

  2. 可配置加载完成后索要循环的片段

  3. 帧数看json文件开头就可

  4. 我看到动画文件的信息:
    "fr":30 - 帧率30fps
    "ip":0 - 起始帧0
    "op":124 - 结束帧124

    'use client'

    import { useEffect, useRef } from 'react'
    import lottie from 'lottie-web'

    interface LottieAnimationProps {
    path?: string
    animationData?: unknown
    className?: string
    width?: number | string
    height?: number | string
    renderer?: 'svg' | 'canvas' | 'html'
    startFrame?: number
    endFrame?: number
    speed?: number
    speedLoop?: number
    }

    export default function LottieAnimation({
    path,
    animationData,
    className = '',
    width = 500,
    height = 500,
    startFrame = 58,
    endFrame = 124,
    speed = 1,
    speedLoop = 1,
    renderer = 'canvas',
    }: LottieAnimationProps) {
    const containerRef = useRef<HTMLDivElement>(null)
    const animationRef = useRef<any>(null) // eslint-disable-line @typescript-eslint/no-explicit-any
    const isInitializedRef = useRef(false)

    // 使用useRef存储参数,避免依赖变化
    const paramsRef = useRef({
    path,
    animationData,
    startFrame,
    endFrame,
    speed,
    speedLoop,
    renderer
    })

    useEffect(() => {
    if (!containerRef.current || isInitializedRef.current) {
    return;
    }

    复制代码
     isInitializedRef.current = true
     const params = paramsRef.current
     let animation: any = null; // eslint-disable-line @typescript-eslint/no-explicit-any
    
     // 创建动画实例
     animation = lottie.loadAnimation({
       container: containerRef.current!,
       renderer: params.renderer,
       loop: false,
       autoplay: false,
       ...(params.path ? { path: params.path } : { animationData: params.animationData }),
     });
    
     animationRef.current = animation
    
     // 播放状态管理
     let isFirstPlay = true;
     let isLooping = false;
     let currentDirection = -1; // -1: 反向(124→54), 1: 正向(54→124)
    
     // 数据准备完成
     animation.addEventListener('data_ready', () => {
       animation.setSpeed(params.speed);
       // 第一次播放:0-124帧
       animation.goToAndStop(0, true);
       animation.play();
     });
    
     // 双向循环播放函数
     const startLoop = () => {
       if (!isLooping) return;
    
       if (currentDirection === -1) {
         // 反向播放:124→54
         animation.playSegments([params.endFrame, params.startFrame], true);
       } else {
         // 正向播放:54→124
         animation.playSegments([params.startFrame, params.endFrame], true);
       }
     };
    
     // 监听播放完成
     animation.addEventListener('complete', () => {
       if (isFirstPlay) {
         isFirstPlay = false;
         isLooping = true;
         animation.setSpeed(params.speedLoop);
         startLoop();
       } else if (isLooping) {
         // 循环播放完成,切换方向
         currentDirection *= -1;
         startLoop();
       }
     });
    
     return () => {
       isInitializedRef.current = false
       if (animation) {
         animation.removeEventListener('data_ready');
         animation.removeEventListener('complete');
         animation.destroy();
         animationRef.current = null
       }
     };

    }, [])

    return (
    <div
    ref={containerRef}
    className={className}
    style={{ width, height }}
    />
    )
    }

    复制代码
         <LottieAnimation
             path="/lottie_home.json"
             width={500}
             height={500}
             renderer="canvas"
           />
相关推荐
乌索普-14 小时前
基于vue2的简易购物车
开发语言·前端·javascript
走粥14 小时前
使用indexOf查找对象结合Pinia持久化引发的问题
开发语言·前端·javascript
北寻北爱14 小时前
前端加密解密- base64、md5、sha256、AES
前端·vue.js
柒.梧.14 小时前
Redis通用命令+五大核心数据结构
前端·bootstrap·html
Refly14 小时前
【微信接入 OpenClaw 龙虾🦞】10分钟手把手教程完成接入,Claude 模型无限使用
前端·微信·github
恋猫de小郭14 小时前
为什么中转渠道的顶级模型会不好用?这是一个技术问题
前端·人工智能·ai编程
发现一只大呆瓜14 小时前
React-深度拆解 React路由:从实战进阶到底层原理
前端·react.js·面试
不甜情歌14 小时前
搞懂 Promise:告别回调嵌套,再也不怕异步代码乱成麻
前端·javascript
野草arthas14 小时前
什么是视觉层次?为什么需要它?
前端
发现一只大呆瓜14 小时前
React-手把手带你实现 Keep-Alive 效果
前端·react.js·面试