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

Next.js中Spline组件onLoad事件无法准确反映加载时长求助

解决Next.js中Spline组件onLoad事件无法准确反映模型加载时长的问题

在Next.js项目中使用@splinetool/react-spline渲染模型时,组件自带的onLoad事件无法准确对应模型的实际加载完成时间——要么加载提示过早消失(模型还在加载),要么迟迟不消失(模型已加载完成)。现有代码及依赖版本如下:

现有实现代码

import Spline from '@splinetool/react-spline';
import { useState } from 'react';

const Computer = () => {
    const [isPhoneLoading, setIsPhoneLoading] = useState(true);

    const handlePhoneLoad = () => {
        setIsPhoneLoading(false);
      };
    return (
    <>
        {isPhoneLoading && <p className='text-5xl'>Loading...</p>}
        <div className='flex h-96 w-full mt-20 mr-20 md:hidden'>
            <div className='w-full'>
                <Spline scene="https://prod.spline.design/jEOSwsR2XIbxiR7J/scene.splinecode" onLoad={handlePhoneLoad}/>
            </div>
        </div>
    </>
     );
}
 
export default Computer;

依赖版本

{
    "@splinetool/react-spline": "^2.2.6",
    "@splinetool/runtime": "^0.9.330",
    "spline": "^0.0.0",
    "@types/react": "18.2.6",
    "@types/react-dom": "18.2.4",
    "next": "13.4.1"
}

尝试过监听onLoad事件的disposed属性,但问题依旧。


解决方案:利用Spline Runtime监听实际加载状态

组件自带的onLoad仅触发组件DOM挂载完成,而非场景所有资源(模型、纹理、动画等)加载完毕。我们可以通过@splinetool/runtime提供的API,直接监听场景的加载事件:

方法1:监听场景全局加载完成事件

通过ref获取Spline实例,监听load事件(该事件在场景所有资源加载完成后触发):

import Spline from '@splinetool/react-spline';
import { useState, useRef, useEffect } from 'react';

const Computer = () => {
  const [isPhoneLoading, setIsPhoneLoading] = useState(true);
  const splineRef = useRef(null);

  useEffect(() => {
    const handleSceneLoad = () => {
      setIsPhoneLoading(false);
    };

    const splineInstance = splineRef.current?.spline;
    if (splineInstance) {
      // 监听场景加载完成事件
      splineInstance.addEventListener('load', handleSceneLoad);
      
      // 若场景已提前加载完成,直接更新状态
      if (splineInstance.scene.isLoaded) {
        setIsPhoneLoading(false);
      }

      // 组件卸载时清理事件监听
      return () => {
        splineInstance.removeEventListener('load', handleSceneLoad);
      };
    }
  }, []);

  return (
    <>
      {isPhoneLoading && <p className='text-5xl'>Loading...</p>}
      <div className='flex h-96 w-full mt-20 mr-20 md:hidden'>
        <div className='w-full'>
          <Spline 
            ref={splineRef}
            scene="https://prod.spline.design/jEOSwsR2XIbxiR7J/scene.splinecode"
          />
        </div>
      </div>
    </>
  );
};

export default Computer;

方法2:监听单个资产加载(适合多资源场景)

如果场景包含大量资产,需要精准统计每个资源的加载状态,可以监听assetLoaded事件,对比已加载资产数和总资产数:

import Spline from '@splinetool/react-spline';
import { useState, useRef, useEffect } from 'react';

const Computer = () => {
  const [isPhoneLoading, setIsPhoneLoading] = useState(true);
  const splineRef = useRef(null);

  useEffect(() => {
    let loadedAssets = 0;
    let totalAssets = 0;

    const splineInstance = splineRef.current?.spline;
    if (!splineInstance) return;

    // 单个资产加载完成时触发
    const handleAssetLoaded = () => {
      loadedAssets++;
      if (loadedAssets === totalAssets) {
        setIsPhoneLoading(false);
      }
    };

    // 场景加载完成后获取总资产数
    const handleSceneLoad = () => {
      totalAssets = splineInstance.scene.assets.length;
      // 若场景无资产,直接结束加载状态
      if (totalAssets === 0) {
        setIsPhoneLoading(false);
      }
    };

    splineInstance.addEventListener('load', handleSceneLoad);
    splineInstance.addEventListener('assetLoaded', handleAssetLoaded);

    return () => {
      splineInstance.removeEventListener('load', handleSceneLoad);
      splineInstance.removeEventListener('assetLoaded', handleAssetLoaded);
    };
  }, []);

  return (
    <>
      {isPhoneLoading && <p className='text-5xl'>Loading...</p>}
      <div className='flex h-96 w-full mt-20 mr-20 md:hidden'>
        <div className='w-full'>
          <Spline 
            ref={splineRef}
            scene="https://prod.spline.design/jEOSwsR2XIbxiR7J/scene.splinecode"
          />
        </div>
      </div>
    </>
  );
};

export default Computer;

说明

  • splineRef.current?.spline获取的是@splinetool/runtime的Runtime实例,通过它可以直接操作Spline场景的底层API。
  • load事件是场景所有资源加载完成的全局触发点,assetLoaded则是每个资源加载完成时触发,可根据场景复杂度选择使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 00:45:03