公共功能
本文把此前在各广告类型文档中反复出现的“公共概念”集中到一处,便于维护,同时让各广告类型文档可以专注于 各自类型特有的功能。
// 1) SDK 初始化(应用全局仅一次)
AdStage.init({
apiKey: 'your-api-key',
debug: process.env.NODE_ENV === 'development'
});
// 2) 容器 DOM 准备好后调用(id 或 Element 均可)
AdStage.ads.banner('banner-container', { /* 选项 */ });
// AdStage.ads.text(element, { /* 选项 */ });
// AdStage.ads.video('video-wrapper', { /* 选项 */ });
// 3) 需要时手动移除(大多数情况不需要:支持自动清理)
AdStage.ads.destroy(slotId);
import { AdStageProvider, useAdStageInstance } from '@adstage/web-sdk';
// layout / root
<AdStageProvider config={{ apiKey: process.env.NEXT_PUBLIC_ADSTAGE_API_KEY, debug: true }}>
{children}
</AdStageProvider>
// 单个组件
function BannerSlot() {
const adstage = useAdStageInstance();
const ref = useRef(null);
useEffect(() => {
if (!adstage || !ref.current) return;
const id = adstage.ads.banner(ref.current, { width: '100%', height: 250 });
return () => adstage.ads.destroy(id);
}, [adstage]);
return <div ref={ref} style={{ height: 250 }} />;
}
| 选项 | 类型 | 说明 | 适用对象 |
|---|
onClick | function(adData) | 广告被点击时的回调 | 全部类型 |
adId | string | 强制指定特定广告 | 全部类型 |
language | 'ko' | 'en' | 'ja' | 'zh' | 语言筛选 | 全部类型 |
deviceType | 'MOBILE' | 'DESKTOP' | 设备筛选 | 全部类型 |
country | 国家代码 (ISO2) | 国家筛选 | 全部类型 |
各广告类型的专有选项请参考对应文档(横幅/文本/视频)。
graph TD
A[调用 init] --> B[调用 slot 函数]
B --> C[查找容器 / 重试]
C --> D[向服务器请求广告]
D --> E[异步加载]
E --> F[渲染]
F --> G[展示跟踪]
G --> H[点击 / 互动跟踪]
- 立即返回型:
slotId 在服务器响应之前就立即返回 ⇒ 不阻塞 UI
- 支持延迟出现的容器:即使容器尚未进入 DOM,也会在一段时间内重试,挂载后即渲染
- 基于 MutationObserver 的自动清理:DOM 被移除时自动执行
destroy()
- 多广告安全:对同一容器重复调用时仅最后一次调用有效(实现层策略)
// 모든 슬롯 정보
const all = AdStage.ads.getAllSlots();
// 특정 슬롯 조회
const slot = AdStage.ads.getSlotById(slotId);
// 수동 제거 (필요한 경우)
AdStage.ads.destroy(slotId);
广告位对象(实际字段):
interface AdSlot {
id: string; // 广告位 ID (slotId)
containerId: string; // 容器 DOM id
adType: 'BANNER' | 'TEXT' | 'VIDEO' | 'NATIVE' | 'INTERSTITIAL' | 'POPUP';
width: number | string; // 数字(px) 或字符串('100%' 等)
height: number | string; // 数字(px) 或字符串('auto' 等)
isLoaded: boolean; // 广告是否加载完成
isVisible: boolean; // 展示状态
refreshRate: number; // 自动刷新周期(秒)
lazyLoad: boolean; // 是否延迟加载
targeting: Record<string, any>;
// 广告位方法
load(): Promise<Advertisement | null>;
render(ad: Advertisement): void;
refresh(): Promise<void>;
destroy(): void;
}
| 策略 | 说明 | 备注 |
|---|
| 后台加载 | 异步加载,不阻塞首次渲染 | slotId 可立即使用 |
| 支持延迟容器 | 自动处理 DOM 稍后插入的情况 | 简化初始化代码 |
| 自动清理 | 防止内存/事件泄漏 | SPA 路由切换时很有用 |
| 最小化 DOM 操作 | 仅更新容器内部的 DOM | 把对父级布局的影响降到最低 |
| 按类型优化尺寸 | 横幅/视频指定尺寸,文本高度自适应 | 降低 CLS |
function selectDeviceType() {
return window.innerWidth <= 768 ? 'MOBILE' : 'DESKTOP';
}
const base = { language: 'ko', deviceType: selectDeviceType() };
const id = AdStage.ads.banner('rwd-banner', { width: '100%', height: 250, ...base });
window.addEventListener('resize', () => {
AdStage.ads.destroy(id);
const next = AdStage.ads.banner('rwd-banner', { width: '100%', height: 250, deviceType: selectDeviceType() });
});
| 模式 | 说明 | 使用时机 |
|---|
| Provider 全局初始化 | 只配置一次 SDK | App/RootLayout |
| 钩子(useAdStageInstance) | 安全地访问 SDK | CSR 组件 |
| 在 useEffect 中 cleanup | 确保执行 destroy | 明确广告位的生命周期 |
| 骨架屏样式 | 自定义 .adstage-loading 状态 | 改善 UX |
.adstage-ad, .adstage-text-ad, .adstage-video-ad { position: relative; overflow: hidden; }
.adstage-loading { opacity: .6; transition: opacity .15s; }
.adstage-loaded { opacity: 1; }
.adstage-error { outline: 1px solid #f87171; }
各类型的额外样式请参考对应文档。
AdStage.init({ apiKey: 'your-api-key', debug: true });
SDK 不会派发 adstage:ad:loaded / adstage:ad:error 之类的 DOM CustomEvent。如果需要广告交互钩子,请在创建广告位时传入 onClick 回调。
AdStage.ads.banner('banner-container', {
width: '100%',
height: 250,
onClick: (adData) => {
console.log('광고 클릭됨:', adData);
// 추가 추적/라우팅 로직
}
});
是否加载完成,可以通过轮询广告位的 isLoaded 字段来确认(开启调试模式后,加载成功/失败会输出到控制台)。
const slotId = AdStage.ads.banner('banner-container', { width: '100%', height: 250 });
const timer = setInterval(() => {
const slot = AdStage.ads.getSlotById(slotId);
if (slot?.isLoaded) {
console.log('로드 완료:', slot);
clearInterval(timer);
}
}, 200);
function dumpAdStage() {
const slots = AdStage.ads.getAllSlots();
console.table(slots.map(s => ({
id: s.id,
containerId: s.containerId,
adType: s.adType,
isLoaded: s.isLoaded
})));
}
| 主题 | 建议 |
|---|
| API Key | 可以公开暴露,但建议使用权限最小化的密钥 |
| 事件跟踪 | 在 onClick 中做额外跟踪时,建议异步发送后再跳转 |
| 错误处理 | 用调试模式的控制台日志与广告位的 isLoaded 状态诊断加载失败 |
| 重试策略 | 容器延迟插入的情况 SDK 自行处理 → 避免滥用额外的 setTimeout |
Q. 一定要调用 destroy() 吗?
A. 大多数情况下不需要。SDK 会自动检测 DOM 被移除。不过,如果要把同一容器立即用于其他用途,建议手动调用 destroy()。
Q. 广告没有出现,但 slotId 有返回。
A. 可能正在异步加载,或者被筛选条件(adId / language / deviceType / country)过滤掉了。请启用调试模式并查看事件日志。
Q. 在 SSR(Next.js)中会在服务器端渲染吗?
A. 不会。广告渲染只在客户端执行。请在 use client 组件内部调用。
Q. 对同一位置连续调用会怎样?
A. 按实现策略,原有广告位会被移除,并以最后一次调用为准保留。