如何在React-Three-Fiber中实现点击触发useFrame动画并在指定时长后停止?
解决React-Three-Fiber中点击动画2秒后停止的问题
嘿,这个需求很常见,我来给你几个实用的解决方案,都是基于你现有代码的改造:
方案一:使用setTimeout + useState(简单直观)
这个思路很直接:点击时开启动画状态,同时用setTimeout在2秒后关闭状态。需要注意清理定时器,防止组件卸载时的内存泄漏。
import { useState, useEffect, useRef } from 'react' import { useFrame } from '@react-three/fiber' function YourComponent() { const group = useRef(null) const [isAnimating, setIsAnimating] = useState(false) const animationTimer = useRef(null) // 点击触发动画的函数 const handleClick = () => { setIsAnimating(true) // 2秒后停止动画 animationTimer.current = setTimeout(() => { setIsAnimating(false) }, 2000) } // 组件卸载时清理定时器 useEffect(() => { return () => { if (animationTimer.current) clearTimeout(animationTimer.current) } }, []) useFrame((state, delta) => { if (isAnimating) { group.current.rotation.x += 0.01 * delta * 60 // 乘以delta*60让速度和帧率无关,更稳定 } }) return ( <group ref={group} onClick={handleClick}> {/* 你的3D内容 */} </group> ) }
小贴士:这里给旋转速度乘了delta * 60,是为了让动画速度不随帧率变化,在不同设备上保持一致,比固定加0.01更靠谱哦~
方案二:使用时间戳追踪动画时长(更精准)
如果想避免定时器和帧循环的潜在偏差,可以用时间戳来计算动画已经运行了多久,超过2秒就停止。这种方式更贴合useFrame的帧循环逻辑:
import { useRef } from 'react' import { useFrame } from '@react-three/fiber' function YourComponent() { const group = useRef(null) const animationStartTime = useRef(null) // 记录动画开始的时间戳 const handleClick = () => { animationStartTime.current = performance.now() // 点击时记录当前时间 } useFrame((state, delta) => { if (!animationStartTime.current) return const elapsedTime = performance.now() - animationStartTime.current if (elapsedTime < 2000) { // 动画还在2秒内,继续旋转 group.current.rotation.x += 0.01 * delta * 60 } else { // 超过2秒,重置状态 animationStartTime.current = null } }) return ( <group ref={group} onClick={handleClick}> {/* 你的3D内容 */} </group> ) }
这个方案不需要额外的state,直接用ref追踪时间,避免了状态更新带来的重渲染,性能更优,时间控制也更精准。
方案三:用动画库(如GSAP)简化逻辑
如果你的项目已经在用GSAP这类动画库,可以直接用它来控制动画时长,代码会更简洁:
import { useRef } from 'react' import gsap from 'gsap' function YourComponent() { const group = useRef(null) const handleClick = () => { // 启动一个2秒的旋转动画,完成后自动停止 gsap.to(group.current.rotation, { x: group.current.rotation.x + (0.01 * 60 * 2), // 计算2秒内要旋转的总角度 duration: 2, ease: 'linear' }) } return ( <group ref={group} onClick={handleClick}> {/* 你的3D内容 */} </group> ) }
这种方式不需要自己管理帧循环,GSAP会帮你处理动画的启停和缓动,适合复杂动画场景。
内容的提问来源于stack exchange,提问作者Achi
相关产品推荐
相关产品推荐

