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(null)
    const animationRef = useRef(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"
           />
相关推荐
计算机魔术师几秒前
Anthropic 自己承认:模型越来越难管住了
前端
两只羊ovo9 分钟前
Agent 干活的底层地基:path 路径 + fs 文件系统,一次讲透
前端
一用书生10 分钟前
我给 ChatGPT、DeepSeek、Kimi 都加了一个「保存为笔记」按钮
前端·ai编程·vibecoding
咖啡无伴侣12 分钟前
1. 从零搭建企业级 Monorepo 工程化模板:初始化、应用创建与共享 TypeScript 配置
前端·前端框架
moonsims13 分钟前
再议AiBrainBox-V的前左右三目布局-满足多目SLAM算法;对比单下视VIO(低空、地面纹理丰富、飞行速度适中无人机 )&多目VIO
前端·人工智能·量子计算
AI编程实验室14 分钟前
Agent Handoff 自动跟踪 Skill:安装、事件映射与证据分级
前端·ai编程
KoPa15 分钟前
HeySmart:事件总线——异步解耦的艺术
前端·后端
金花顺15 分钟前
ndroid 音频系统:AudioTrack 源码深度解析(从 Java 构造到 Native 启动)
前端·架构
用户9210802628615 分钟前
AI SSE Client 和普通 SSE Client 有什么不同:一次生成任务背后的坑与设计边界
前端
PedroQue9924 分钟前
@meng-xi/create-uni-app v1.0.0 正式发布
前端·uni-app