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"
           />
相关推荐
老华带你飞7 分钟前
学生请假管理|基于springboot 学生请假管理系统(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·后端·spring
前端不太难23 分钟前
如何给 RN 项目设计「不会失控」的导航分层模型
前端·javascript·架构
用户40993225021227 分钟前
Vue3中v-show如何通过CSS修改display属性控制条件显示?与v-if的应用场景该如何区分?
前端·javascript·vue.js
不会聊天真君64734 分钟前
CSS3(Web前端开发笔记第二期)
前端·笔记·css3
discode39 分钟前
【开源项目技术分享】@host-navs 站导,一个简洁高效的网站链接导航工具站
前端
PieroPC43 分钟前
Nicegui 3.4.0 可以缩小组件之间的间距 label botton input textarea
前端
写代码的皮筏艇1 小时前
数组 forEach
前端·javascript
bytemanx1 小时前
深入源码:React 19 useActionState 与 Next.js Server Actions 的完美融合
react.js·next.js