共用功能
本文將過去在各廣告類型文件中重複出現的「共用概念」集中於一處,方便維護,同時讓各廣告類型文件能專注於 各自類型專屬的功能。
// 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 |
| Hook(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. 依實作策略,既有版位會被移除,並以最後一次呼叫為準保留。