如何正确制作页面preloader 实现等待页面完全加载后自动消失
Preloader 实现思路与技巧
以下是几种可以精准监听页面加载状态、无需固定定时器的实现方案:
方案1:原生加载事件 + 请求计数器组合
这个方案适合所有类型的站点,兼容性最好:
- 先监听
window.load事件,该事件会等待页面所有关联静态资源(图片、字体、样式、同步脚本)加载完成后才触发,注意不要仅依赖DOMContentLoaded事件,后者仅在DOM解析完成时触发,不会等静态资源和异步请求。 - 给所有初始数据请求增加计数逻辑:定义全局变量
pendingRequests等于初始请求的总数量,每个请求完成(无论成功失败)时将计数减1。 - 当
window.load触发且pendingRequests计数归0时,再隐藏preloader。
简单实现示例:
let pendingRequests = 3; // 替换为你实际的初始请求数量 let isPageStaticLoaded = false; // 每个初始请求结束时调用该方法 function finishRequest() { pendingRequests--; tryHidePreloader(); } // 监听静态资源加载完成 window.addEventListener('load', () => { isPageStaticLoaded = true; tryHidePreloader(); }); function tryHidePreloader() { if (pendingRequests === 0 && isPageStaticLoaded) { document.querySelector('.preloader').style.display = 'none'; } }
如果使用Axios等请求库,可以直接在响应拦截器里统一处理计数逻辑,不用手动给每个请求加回调。
方案2:Promise 统一管理所有初始任务
适合单页应用、所有初始加载逻辑可控的场景:
- 把所有需要等待的任务(初始接口请求、首屏特殊资源预加载、自定义初始化逻辑)全部封装为Promise,放到同一个数组中。
- 使用
Promise.allSettled监听所有任务完成,就算某个请求失败也不会导致preloader永远不消失。
简单实现示例:
// 整合所有初始加载任务 const initLoadTasks = [ fetch('/api/init-config'), fetch('/api/user-info'), // 可加入自定义资源加载任务,比如首屏大图 new Promise((resolve) => { const heroImage = document.querySelector('.hero img'); heroImage.complete ? resolve() : heroImage.onload = resolve; }) ]; // 所有任务完成后隐藏加载器 Promise.allSettled(initLoadTasks).then(() => { document.querySelector('.preloader').classList.add('preloader--hide'); });
通用优化技巧
- 增加最小显示时长:避免页面加载速度太快导致preloader闪一下就消失,体验割裂,可以设置至少300ms的最小显示时间,计算preloader已显示时长,不足就用
setTimeout延迟隐藏。 - 增加最长兜底时长:设置10s左右的最长显示时间,就算有请求卡住也会自动隐藏preloader,避免用户永远无法访问页面。
- 可搭配进度提示:如果初始任务数量固定,可以根据已完成任务数计算加载进度,给用户更明确的反馈。
内容的提问来源于stack exchange,提问作者mmm42
相关产品推荐
相关产品推荐

