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"
           />
相关推荐
05Nuyoah2 小时前
DAY 04 CSS文本,字体属性以及选择器
前端·css
一條狗2 小时前
学习日报 20250928|React 中实现 “实时检测”:useEffect 依赖项触发机制详解
前端·react.js
Gazer_S2 小时前
【React 状态管理深度解析:Object.is()、Hook 机制与 Vue 对比实践指南】
前端·react.js·前端框架
Nicholas682 小时前
flutter视频播放器video_player_avfoundation之AVFoundationVideoPlayer(三)
前端
Asort2 小时前
JavaScript设计模式(六)——适配器模式 (Adapter)
前端·javascript·设计模式
是晓晓吖2 小时前
Puppeteer page.on('response',fn)的最佳实践之等待响应
前端·puppeteer
跟橙姐学代码3 小时前
给Python项目加个“隔离间”,从此告别依赖纠缠!
前端·python·ipython
Cache技术分享3 小时前
202. Java 异常 - throw 语句的使用
前端·后端