app-template/packages/adsense/src/react/AdSlot.tsx

77 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}
/>
);
}