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
相关产品推荐
相关产品推荐

