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

如何在页面(含外部资源)加载完成前显示加载动画?

页面加载动画未检测全部资源的问题排查与解决

我希望在页面**完全加载(包括外部广告横幅等资源)**前显示加载动画,目前用以下代码实现加载动画的显示与过渡隐藏,但怀疑当前逻辑没有检测到所有页面资源:

HTML代码

<div class="loader"></div>

CSS代码

.loader {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #333333;
  transition: opacity 0.75s, visibility 0.75s;
}

.loader--hidden {
  opacity: 0;
  visibility: hidden;
}

.loader::after {
  content: "";
  width: 75px;
  height: 75px;
  border: 15px solid #dddddd;
  border-top-color: #009578;
  border-radius: 50%;
  animation: loading 0.75s ease infinite;
}

@keyframes loading {
  from {
    transform: rotate(0turn);
  }
  to {
    transform: rotate(1turn);
  }
}

JS代码

window.addEventListener("load", () => {
  const loader = document.querySelector(".loader");

  loader.classList.add("loader--hidden");

  loader.addEventListener("transitionend", () => {
    document.body.removeChild(loader);
  });
});

我参考了相关代码实现,但目前的逻辑可能存在资源检测不全的问题。


问题分析

window.load事件确实会等待页面初始资源(图片、样式表、脚本、iframe等)加载完成后触发,但广告横幅这类由第三方脚本动态加载的资源,往往不会被window.load覆盖——因为这类广告通常是页面初始资源加载完成后,由JS动态创建元素并发起请求,这时候window.load已经触发,导致加载动画提前隐藏,广告还在加载。

解决方案

1. 追踪广告资源加载状态

如果广告平台提供加载完成的回调(比如多数平台会有onAdLoaded类事件),可以同时监听页面load事件和广告加载回调,等两者都完成后再隐藏加载动画:

let pageLoaded = false;
let adLoaded = false;

// 监听页面初始资源加载完成
window.addEventListener("load", () => {
  pageLoaded = true;
  checkAllLoaded();
});

// 监听广告加载完成(需根据广告平台实际事件名调整)
window.addEventListener("adLoaded", () => {
  adLoaded = true;
  checkAllLoaded();
});

// 统一检查所有资源加载状态
function checkAllLoaded() {
  if (pageLoaded && adLoaded) {
    const loader = document.querySelector(".loader");
    loader.classList.add("loader--hidden");
    loader.addEventListener("transitionend", (e) => {
      // 避免transitionend多次触发
      if (e.propertyName === "opacity") {
        document.body.removeChild(loader);
      }
    });
  }
}

2. 兜底方案:动态检测DOM变化

如果广告平台没有提供加载回调,可以通过监听广告容器的DOM变化,结合定时器兜底:

window.addEventListener("load", () => {
  const loader = document.querySelector(".loader");
  const adContainer = document.querySelector("#ad-container"); // 替换为你的广告容器选择器
  
  // 监听广告容器的DOM节点变化
  const observer = new MutationObserver((mutations) => {
    mutations.forEach((mutation) => {
      if (mutation.addedNodes.length > 0) {
        // 根据广告元素特征判断是否加载完成(示例:检测iframe或带ad类名的元素)
        const hasAd = Array.from(mutation.addedNodes).some(node => 
          node.tagName === "IFRAME" || node.classList.contains("ad-banner")
        );
        if (hasAd) {
          // 给广告内容预留加载时间
          setTimeout(() => {
            hideLoader(loader);
            observer.disconnect();
          }, 500);
        }
      }
    });
  });

  observer.observe(adContainer, { childList: true, subtree: true });

  // 兜底定时器:避免广告加载异常导致动画一直显示
  setTimeout(() => {
    hideLoader(loader);
    observer.disconnect();
  }, 5000); // 5秒后强制隐藏
});

function hideLoader(loader) {
  loader.classList.add("loader--hidden");
  loader.addEventListener("transitionend", (e) => {
    if (e.propertyName === "opacity") {
      document.body.removeChild(loader);
    }
  });
}

3. 修复过渡事件重复触发问题

当前代码中transitionend会因opacity和visibility两个属性的过渡各触发一次,可通过判断属性名只执行一次移除操作:

loader.addEventListener("transitionend", (e) => {
  if (e.propertyName === "opacity") {
    document.body.removeChild(loader);
  }
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 05:50:25