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"
           />
相关推荐
yuzhiboyouye34 分钟前
web前端英语面试
前端·面试·状态模式
canonical_entropy2 小时前
下一代低代码渲染框架 nop-chaos-flux 的设计原则
前端·低代码·前端框架
东方小月2 小时前
5分钟搞懂Harness Engineering(驾驭工程):从提示词到AI Agent的进化之路
前端·后端·架构
我叫黑大帅2 小时前
为什么需要 @types/react?解决“无法找到模块 react 的声明文件”报错
前端·javascript·面试
之歆2 小时前
DAY_21JavaScript 深度解析:数组(Array)与函数(Function)(一)
前端·javascript
XinZong3 小时前
【AI社交】基于OpenClaw自研轻量化AI社交平台实战
前端
Le_ee3 小时前
ctfweb:php/php短标签/.haccess+图片马/XXE
开发语言·前端·php
爱上好庆祝3 小时前
学习js的第七天(wed APIs的开始)
前端·javascript·css·学习·html·css3
KaMeidebaby4 小时前
卡梅德生物技术快报|冻干工艺开发:注射用心肌肽全流程参数优化与工程化方案
前端·其他·百度·新浪微博
Moment5 小时前
面试官:如果产品经理给你多个需求,怎么让AI去完成❓❓❓
前端·后端·面试