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

如何在react-fiber/drei的<Text>组件中实现透明度过渡动画

问题描述

想用react-fiber/drei的<Text>组件实现从0到1的透明度过渡动画,试了react-spring/three但没效果,代码如下:

import { useEffect, useRef, useState} from "react";
import { Text } from "@react-three/drei";
import { animated, useSpring } from "@react-spring/three";

function Cube() {
    const meshRef = useRef<Mesh>(null);
    const styles = useSpring({
        from: {
          opacity: 0
        },
        to: {
          opacity: 1
        }, 
        delay: 1000,
      })

    return (
        <group>
          <Text
                position={[0, 0, 0]}
                fontSize={1}
                color="white"
                anchorX="center"
                anchorY="middle"
                fillOpacity={styles.opacity as any}
             >
           test
          </Text> 
        </group>
    );
  }

请问react-spring/three失效时,还有其他框架可用吗?或者必须手动写动画?


解决方案

一、先修复react-spring/three的用法问题

你的代码没给<Text>套animated包装器,react-spring需要通过animated组件劫持目标组件的属性才能驱动动画,而且属性绑定要用到正确的插值语法。修改后代码如下:

import { useRef } from "react";
import { Text } from "@react-three/drei";
import { animated, useSpring } from "@react-spring/three";

// 用animated包装Text组件
const AnimatedText = animated(Text);

function Cube() {
    const styles = useSpring({
        from: { fillOpacity: 0 },
        to: { fillOpacity: 1 },
        delay: 1000,
    })

    return (
        <group>
            <AnimatedText
                position={[0, 0, 0]}
                fontSize={1}
                color="white"
                anchorX="center"
                anchorY="middle"
                {...styles} // 直接展开spring样式
            >
                test
            </AnimatedText>
        </group>
    );
}

这里把fillOpacity直接放进spring配置,再展开到AnimatedText上,react-spring就能正确驱动这个属性的动画了。

二、替代框架:framer-motion/three

如果还是觉得react-spring不好用,可以试试framer-motion的three适配版本,用法更直观:

import { Text } from "@react-three/drei";
import { motion } from "framer-motion/three";

function Cube() {
    return (
        <group>
            <motion(Text)
                position={[0, 0, 0]}
                fontSize={1}
                color="white"
                anchorX="center"
                anchorY="middle"
                initial={{ fillOpacity: 0 }}
                animate={{ fillOpacity: 1 }}
                transition={{ delay: 1 }}
            >
                test
            </motion(Text)>
        </group>
    );
}

三、手动实现过渡动画

不想用第三方库的话,也可以结合useState和requestAnimationFrame手动写,或者用gsap这类动画库直接操作组件:

方式1:原生requestAnimationFrame

import { useEffect, useState } from "react";
import { Text } from "@react-three/drei";

function Cube() {
    const [fillOpacity, setFillOpacity] = useState(0);

    useEffect(() => {
        let startTime: number | null = null;
        const duration = 1000; // 动画时长1秒
        const delay = 1000; // 延迟1秒启动

        function animate(timestamp: number) {
            if (!startTime) startTime = timestamp;
            // 计算延迟后的时间进度
            const elapsed = timestamp - startTime - delay;
            const progress = Math.min(elapsed / duration, 1);
            if (progress >= 0) {
                setFillOpacity(progress);
            }
            if (progress < 1) {
                requestAnimationFrame(animate);
            }
        }

        const frameId = requestAnimationFrame(animate);
        return () => cancelAnimationFrame(frameId);
    }, []);

    return (
        <group>
            <Text
                position={[0, 0, 0]}
                fontSize={1}
                color="white"
                anchorX="center"
                anchorY="middle"
                fillOpacity={fillOpacity}
            >
                test
            </Text>
        </group>
    );
}

方式2:用gsap直接控制

import { useEffect, useRef } from "react";
import { Text } from "@react-three/drei";
import gsap from "gsap";

function Cube() {
    const textRef = useRef<any>(null);

    useEffect(() => {
        gsap.fromTo(textRef.current, 
            { fillOpacity: 0 }, 
            { fillOpacity: 1, delay: 1, duration: 1 }
        );
    }, []);

    return (
        <group>
            <Text
                ref={textRef}
                position={[0, 0, 0]}
                fontSize={1}
                color="white"
                anchorX="center"
                anchorY="middle"
            >
                test
            </Text>
        </group>
    );
}

内容的提问来源于stack exchange,提问作者NiceBro

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 09:53:10