77 lines
2.3 KiB
TypeScript
77 lines
2.3 KiB
TypeScript
import { useEffect, useRef, type CSSProperties } from "react";
|
||
import { loadAdSense, pushAdSense } from "../loader.js";
|
||
|
||
export interface AdSlotProps {
|
||
/** 广告单元 ID(data-ad-slot) */
|
||
adSlot: string;
|
||
/** 发布商 ID(data-ad-client,形如 ca-pub-xxxxxxxx) */
|
||
adClient: string;
|
||
/** data-ad-format,默认 auto */
|
||
format?: string | undefined;
|
||
/** data-ad-layout */
|
||
layout?: string | undefined;
|
||
/** data-ad-layout-key */
|
||
layoutKey?: string | undefined;
|
||
/** data-full-width-responsive,未传时不输出该属性 */
|
||
fullWidthResponsive?: boolean | undefined;
|
||
className?: string | undefined;
|
||
style?: CSSProperties | undefined;
|
||
}
|
||
|
||
/**
|
||
* AdSense 广告位组件:渲染 <ins class="adsbygoogle">,
|
||
* 挂载后按需加载官方脚本并 push 渲染命令。
|
||
*
|
||
* 注意:属性名刻意避开 Astro 的 `slot` / `client:*` 保留字,
|
||
* 在 Astro island 中可直接透传。
|
||
*/
|
||
export function AdSlot({
|
||
adSlot,
|
||
adClient,
|
||
format = "auto",
|
||
layout,
|
||
layoutKey,
|
||
fullWidthResponsive,
|
||
className,
|
||
style,
|
||
}: AdSlotProps) {
|
||
const pushedKeyRef = useRef<string | null>(null);
|
||
|
||
// 按 adClient#adSlot 去重 push;StrictMode 双调用与依赖重跑都安全
|
||
useEffect(() => {
|
||
let cancelled = false;
|
||
const key = `${adClient}#${adSlot}`;
|
||
|
||
loadAdSense(adClient)
|
||
.then(() => {
|
||
if (cancelled || pushedKeyRef.current === key) {
|
||
return;
|
||
}
|
||
pushedKeyRef.current = key;
|
||
pushAdSense();
|
||
})
|
||
.catch((err: unknown) => {
|
||
console.error("[adsense]", err);
|
||
});
|
||
|
||
return () => {
|
||
cancelled = true;
|
||
};
|
||
}, [adClient, adSlot]);
|
||
|
||
return (
|
||
<ins
|
||
className={className ? `adsbygoogle ${className}` : "adsbygoogle"}
|
||
style={{ display: "block", ...style }}
|
||
data-ad-client={adClient}
|
||
data-ad-slot={adSlot}
|
||
data-ad-format={format}
|
||
data-ad-layout={layout}
|
||
data-ad-layout-key={layoutKey}
|
||
data-full-width-responsive={
|
||
fullWidthResponsive === undefined ? undefined : String(fullWidthResponsive)
|
||
}
|
||
/>
|
||
);
|
||
}
|