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

在React或React Router中如何监听window.loaded事件检测页面资源全加载?

SPA路由切换页面全资源加载完成检测方案

核心思路

单页应用路由切换不会触发页面重载,因此原生window.load事件仅首次进入应用时触发。我们可以通过路由级资源主动监听的方案实现需求,核心逻辑是每次路由切换后,主动收集当前页面所有待加载的资源URL,逐个监听加载状态,全部资源加载完成(含加载失败场景)后触发完成回调。

具体实现步骤

  • 封装路由页面通用包裹组件,所有路由对应页面均用该组件包裹,自动监听路由切换时机
  • 路由切换触发包裹组件挂载/更新时,收集当前页面所有资源URL:
    • 遍历DOM获取所有<img>标签的src属性
    • 提取所有DOM元素的background-image属性中的资源路径
    • 异步加载组件(React.lazy/动态import)在组件resolve后补充收集内部资源
  • 为每个资源创建对应实例监听加载状态,维护加载计数器,所有资源触发load/error事件后计数器归零,即判定为当前页面资源加载完成

代码示例

import { useEffect, useRef } from 'react';
import { useLocation } from 'react-router-dom';

const PageResourceListener = ({ children, onAllLoaded }) => {
  const location = useLocation();
  const resourceCountRef = useRef(0);
  const loadedCountRef = useRef(0);

  // 单个资源加载完成的回调
  const handleResourceLoad = () => {
    loadedCountRef.current += 1;
    if (loadedCountRef.current === resourceCountRef.current) {
      onAllLoaded?.();
    }
  };

  useEffect(() => {
    // 路由切换时重置计数器
    resourceCountRef.current = 0;
    loadedCountRef.current = 0;

    // 等待页面组件DOM挂载完成后收集资源
    setTimeout(() => {
      // 收集所有img标签资源
      const imgs = Array.from(document.querySelectorAll('img'));
      // 收集所有带background-image的元素资源
      const bgElements = Array.from(document.querySelectorAll('*')).filter(el => {
        const bg = getComputedStyle(el).backgroundImage;
        return bg && bg !== 'none';
      });
      const bgUrls = bgElements.map(el => {
        const bg = getComputedStyle(el).backgroundImage;
        return bg.match(/url\(["']?([^"']*)["']?\)/)[1];
      });

      const allResourceUrls = [...imgs.map(img => img.src), ...bgUrls].filter(Boolean);
      resourceCountRef.current = allResourceUrls.length;

      // 没有资源直接触发完成
      if (resourceCountRef.current === 0) {
        onAllLoaded?.();
        return;
      }

      // 逐个监听资源加载
      allResourceUrls.forEach(url => {
        const img = new Image();
        img.src = url;
        img.onload = handleResourceLoad;
        img.onerror = handleResourceLoad; // 加载失败也计入完成,避免卡住
      });
    }, 0);
  }, [location.pathname]); // 路由path变化时重新统计

  return <>{children}</>;
};

// 使用方式:在路由配置处包裹页面组件
// <Route path="/xxx" element={
//   <PageResourceListener onAllLoaded={() => console.log('页面资源全部加载完成')}>
//     <YourPageComponent />
//   </PageResourceListener>
// } />

边界场景处理

  • 如果页面存在动态生成的资源(比如接口返回后才渲染的图片),可以在接口请求完成后手动触发一次资源收集逻辑
  • 字体、音视频等其他类型资源可以扩展对应类型的监听逻辑,比如用FontFaceSetAPI监听字体加载
  • 不需要监听的资源可以添加自定义属性(比如data-ignore-load),收集资源时过滤掉对应元素即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 08:18:01