You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 19:27:44