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

如何用Google Publisher Tag实现可折叠广告位并按需显示?

实现GPT可折叠广告位:无广告时隐藏、加载成功后显示

我需为网站开发可折叠广告位,希望通过Google Publisher Tag实现:无可用广告时隐藏广告位,仅在广告成功加载后显示对应代码块,以此解决广告加载期间的折叠元素问题。请问是否有辅助实现的库或工具?恳请提供相关指导与建议。

核心思路与实现步骤

1. 利用GPT原生事件监听

GPT本身提供了完整的广告状态监听能力,无需额外依赖第三方库就能实现核心需求。关键是监听slotRenderEnded事件:

  • 广告成功渲染(有填充)时,显示广告容器
  • 无广告填充时,隐藏容器并清理占位空间

2. 代码改造建议

针对你提供的React组件,做以下核心修改:

  • 添加状态控制广告容器的显示/隐藏
  • 移除硬编码的占位高度,避免加载期间布局跳动
  • 绑定GPT事件监听,精准判断广告加载状态

修改后的完整代码

import { useMediaQuery } from "@mui/material";
import { useTheme } from "@mui/material/styles";
import { StyleRoot } from "radium";
import React, { useEffect, useRef, useState } from "react";
import Display from "../../Display";
import IMPAd from "../../IMPAd";

const RollingLeaderBoards = (props) => {
  const [isAdLoaded, setIsAdLoaded] = useState(false);
  const adContainerRef = useRef(null);
  const slotRef = useRef(null);

  const adHeight = {
    large: "90px",
    medium: "90px",
    small: "60px",
    xlDesktop: "250px",
    xlMobile: "100px",
  };

  const style = {
    marginBottom: "45px",
    "@media only screen and (min-width: 960px) and (max-width: 1300px)": {
      marginBottom: "45px",
    },
    "@media only screen and (min-width: 0px) and (max-width: 600px)": {
      marginBottom: "30px",
    },
    "@media only screen and (min-width: 600px) and (max-width: 960px)": {
      marginBottom: "30px",
    },
  };

  const theme = useTheme();
  const smallmb = useMediaQuery(theme.breakpoints.between("xs", "sm")); //0 - 600
  const largemb = useMediaQuery(theme.breakpoints.between("sm", "md")); //600 - 960

  let timeout = 500;
  let adHeightType = props.adPosition === "top" ? ["xlDesktop"] : ["medium"];
  let adBlockHeight =
    props.adPosition === "top" ? adHeight["large"] : adHeight["medium"];
  if (smallmb || largemb) {
    adBlockHeight = adHeight["small"];
    adHeightType = "small";
  }
  const topStyle = {
    marginTop: "15px",
    height: adBlockHeight,
  };

  useEffect(() => {
    if (!window.googletag) return;

    // 监听广告渲染完成事件
    window.googletag.pubads().addEventListener('slotRenderEnded', (event) => {
      if (event.slot === slotRef.current) {
        // 有广告填充时显示容器
        setIsAdLoaded(event.creativeId !== undefined);
      }
    });
  }, []);

  const refFunc = (node) => {
    if (node && !slotRef.current) {
      adContainerRef.current = node;
      window.googletag.cmd.push(function () {
        const RollingLeaderBoard = window.googletag
          .defineSlot(
            "/2744311/Display/Display_Push/Leaderboard",
            [
              [970, 250],
              [970, 90],
              [728, 90],
              [320, 50],
              [320, 100],
              [300, 50],
            ],
            `div-RollingLeaderBoard${props.modId}`
          )
          .addService(window.googletag.pubads());
        
        slotRef.current = RollingLeaderBoard;
        RollingLeaderBoard.setTargeting("adpos", `${props.adPosition}`);

        window.googletag.enableServices();
        if (window.isMoatDataAvailable()) {
          window.requestAds();
          window.googletag.display(`div-RollingLeaderBoard${props.modId}`);
          window.googletag.pubads().refresh([RollingLeaderBoard]);
        } else {
          window["moatYieldReady"] = window.requestAds;
          window.googletag.display(`div-RollingLeaderBoard${props.modId}`);
          window.googletag.pubads().refresh([RollingLeaderBoard]);
        }
      });
    }
  };

  return (
    <Display {...props} timeout={timeout}>
      {/* 仅当广告加载成功时渲染容器 */}
      {isAdLoaded && (
        <div
          style={{
            display: "flex",
            justifyContent: "center",
          }}
          id="rollingLeaderBoard"
        >
          <div
            style={{
              width: "100%",
              display: "flex",
              justifyContent: "center",
              marginBottom: "32px",
              marginTop: "32px",
            }}
          >
            <div
              style={{
                position: "sticky",
                maxHeight: "120px",
                display: "flex",
                justifyContent: "center",
                margin: "0px 0 16px 0",
                width: "100%",
                top: "30px",
              }}
            >
              <div style={style}>
                <IMPAd>
                  <StyleRoot>
                    <div
                      id={`div-RollingLeaderBoard${props.modId}`}
                      ref={refFunc}
                      style={topStyle}
                    ></div>
                  </StyleRoot>
                </IMPAd>
              </div>
            </div>
          </div>
        </div>
      )}
    </Display>
  );
};

export default RollingLeaderBoards;

关键改进点说明

  • 新增isAdLoaded状态,完全控制广告容器的渲染逻辑,无广告时不生成占位DOM
  • 通过slotRenderEnded事件精准判断当前广告位的填充状态,避免误判
  • 移除硬编码的灰色背景占位,彻底解决加载期间的布局跳动问题
  • 使用useRef保存广告slot实例,确保事件监听能准确匹配目标广告位

可选工具/库

如果想减少重复代码,可以考虑:

  • 社区GPT封装组件:一些React生态的封装组件内置了广告状态监听、显示控制逻辑,直接复用即可
  • 自定义Hook:把GPT初始化、事件监听逻辑抽成独立Hook,方便在多个广告组件中共享

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 22:03:00