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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 22:55:18