在React或React Router中如何监听window.loaded事件检测页面资源全加载?
SPA路由切换页面全资源加载完成检测方案
核心思路
单页应用路由切换不会触发页面重载,因此原生window.load事件仅首次进入应用时触发。我们可以通过路由级资源主动监听的方案实现需求,核心逻辑是每次路由切换后,主动收集当前页面所有待加载的资源URL,逐个监听加载状态,全部资源加载完成(含加载失败场景)后触发完成回调。
具体实现步骤
- 封装路由页面通用包裹组件,所有路由对应页面均用该组件包裹,自动监听路由切换时机
- 路由切换触发包裹组件挂载/更新时,收集当前页面所有资源URL:
- 遍历DOM获取所有
<img>标签的src属性 - 提取所有DOM元素的
background-image属性中的资源路径 - 异步加载组件(
React.lazy/动态import)在组件resolve后补充收集内部资源
- 遍历DOM获取所有
- 为每个资源创建对应实例监听加载状态,维护加载计数器,所有资源触发
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
相关产品推荐
相关产品推荐

