ReactJS页面切换时显示加载Spinner的问题求助
解决SPA路由切换时Spinner不触发的问题
你的问题核心在于单页应用(SPA)的路由切换不会触发window的load事件——这个事件仅在整个页面首次加载完成时触发一次,后续路由切换只是DOM局部更新,window始终处于loaded状态,所以监听器永远不会执行。而新页面的图片属于动态插入的资源,需要单独监听它们的加载状态。
以下是修正后的实现方案:
import React, { useEffect, useState, useRef } from 'react'; import { useLocation } from 'react-router-dom'; import "./Spinner.css" export function Spinner() { const { pathname } = useLocation(); const [isLoading, setIsLoading] = useState(true); const imageLoadCounts = useRef(0); const imageTotal = useRef(0); useEffect(() => { const body = document.querySelector("body"); body.style.overflow = "hidden"; setIsLoading(true); imageLoadCounts.current = 0; // 获取当前页面所有图片元素 const images = document.querySelectorAll('img'); imageTotal.current = images.length; // 没有图片直接结束加载 if (imageTotal.current === 0) { body.style.overflow = "auto"; setIsLoading(false); return; } // 图片加载完成/失败的处理函数 const handleImageLoad = () => { imageLoadCounts.current += 1; if (imageLoadCounts.current === imageTotal.current) { body.style.overflow = "auto"; setIsLoading(false); } }; // 给每个图片绑定监听事件 images.forEach(img => { // 如果图片已经加载完成(来自缓存),直接触发处理函数 if (img.complete) { handleImageLoad(); } else { img.addEventListener('load', handleImageLoad); img.addEventListener('error', handleImageLoad); // 图片加载失败也算完成 } }); // 清理函数:移除事件监听 return () => { images.forEach(img => { img.removeEventListener('load', handleImageLoad); img.removeEventListener('error', handleImageLoad); }); }; }, [pathname]) return ( isLoading ? <div className="spinner-wrapper"> <div className="spinner"> {/* 修正React属性规范:class改为className */} Loading <div className="spinner-sector spinner-sector-red"></div> <div className="spinner-sector spinner-sector-blue"></div> <div className="spinner-sector spinner-sector-green"></div> </div> </div> : null ) }
关键改进点说明:
- 放弃window.load监听:改用监听当前路由下所有图片的加载状态,适配SPA的DOM局部更新特性。
- 处理缓存图片:判断图片是否已经
complete(来自浏览器缓存),避免这类图片无法触发load事件导致Spinner一直显示。 - 容错处理:监听图片的
error事件,即使图片加载失败,也会结束Spinner状态,避免界面卡住。 - 清理事件监听器:在useEffect的返回函数中移除监听,防止内存泄漏。
- 修正React语法:将JSX中的
class改为className,符合React的属性规范。
额外优化建议:
如果你的页面还有其他异步资源(比如字体、音频)需要等待,可以扩展监听逻辑,比如监听字体加载完成事件,或者结合数据请求的状态(比如接口返回后再隐藏Spinner),根据实际业务场景调整判断条件。
内容的提问来源于stack exchange,提问作者bero
相关产品推荐
相关产品推荐

