-
引入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(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" />
react-lottie动画组件封装
殇蓝2025-09-29 10:59
相关推荐
咩咩啃树皮8 小时前
第40篇:Vue3组件化开发精讲——组件拆分、复用、父子通信、工程化架构阳光是sunny8 小时前
LangGraph中的Reducer是什么触底反弹8 小时前
一文搞懂 Tailwind CSS 弹性布局:从原理到实战阳光是sunny8 小时前
从链到图:LangGraph 入门基础全解析小林ixn9 小时前
从 ??= 到 onKeyDown:一个 React 组件的“自我修养”REDcker9 小时前
显示分辨率标准对照详解এ慕ོ冬℘゜10 小时前
前端实战:jQuery 多条件联合搜索(标题模糊查询 + 日历时间段筛选)武子康10 小时前
Search Console Platform Properties 扩大 SEO 资产边界:从 Page Ranking 到 Topic Coverage(5 类误读边界 + 3 表数据层设计)一点一木10 小时前
从60首歌到1个网站:输入你的故事,还你一首歌IT_陈寒12 小时前
Vue这个特性差点让我加班到凌晨,谁懂啊