-
引入lottie.json即可
-
可配置加载完成后索要循环的片段
-
帧数看json文件开头就可
-
我看到动画文件的信息:
"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" />
react-lottie动画组件封装
殇蓝2025-09-29 10:59
相关推荐
05Nuyoah2 小时前
DAY 04 CSS文本,字体属性以及选择器一條狗2 小时前
学习日报 20250928|React 中实现 “实时检测”:useEffect 依赖项触发机制详解Gazer_S2 小时前
【React 状态管理深度解析:Object.is()、Hook 机制与 Vue 对比实践指南】Nicholas682 小时前
flutter视频播放器video_player_avfoundation之AVFoundationVideoPlayer(三)Asort2 小时前
JavaScript设计模式(六)——适配器模式 (Adapter)是晓晓吖2 小时前
Puppeteer page.on('response',fn)的最佳实践之等待响应跟橙姐学代码3 小时前
给Python项目加个“隔离间”,从此告别依赖纠缠!Cache技术分享3 小时前
202. Java 异常 - throw 语句的使用