import { siteConfig } from '@/lib/config' import { loadExternalResource } from '@/lib/utils' import { useEffect } from 'react' /** * 请求广告元素 * 调用后,实际只有当广告单元在页面中可见时才会真正获取 */ function requestAd(ads) { if (!ads || ads.length === 0) { return } const adsbygoogle = window.adsbygoogle if (adsbygoogle && ads.length > 0) { const observerOptions = { root: null, // use the viewport as the root threshold: 0.5 // element is considered visible when 50% visible } const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { const adStatus = entry.target.getAttribute('data-adsbygoogle-status') if (!adStatus || adStatus !== 'done') { adsbygoogle.push(entry.target) observer.unobserve(entry.target) // stop observing once ad is loaded } } }) }, observerOptions) ads.forEach(ad => { observer.observe(ad) }) } } // 获取节点或其子节点中包含 adsbygoogle 类的节点 function getNodesWithAdsByGoogleClass(node) { const adsNodes = [] // 检查节点及其子节点是否包含 adsbygoogle 类 function checkNodeForAds(node) { if (node.tagName === 'INS' && node.classList.contains('adsbygoogle')) { adsNodes.push(node) } else { // 递归检查子节点 for (let i = 0; i < node.childNodes.length; i++) { checkNodeForAds(node.childNodes[i]) } } } checkNodeForAds(node) return adsNodes } /** * 初始化谷歌广告 * @returns */ export const initGoogleAdsense = async ADSENSE_GOOGLE_ID => { console.log('Load Adsense') loadExternalResource( `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${ADSENSE_GOOGLE_ID}`, 'js' ).then(url => { setTimeout(() => { // 页面加载完成后加载一次广告 const ads = document.querySelectorAll('ins.adsbygoogle') if (window.adsbygoogle && ads.length > 0) { requestAd(Array.from(ads)) } // 创建一个 MutationObserver 实例,监听页面上新出现的广告单元 const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { // 检查每个添加到DOM中的节点 mutation.addedNodes.forEach(node => { // 如果节点是adsbygoogle元素,则请求广告 if (node.nodeType === Node.ELEMENT_NODE) { const adsNodes = getNodesWithAdsByGoogleClass(node) if (adsNodes.length > 0) { requestAd(adsNodes) } } }) }) }) // 配置 MutationObserver 监听特定类型的 DOM 变化 const observerConfig = { childList: true, // 观察目标子节点的变化 subtree: true // 包括目标节点的所有后代节点 } // 启动 MutationObserver observer.observe( document.querySelector('#article-wrapper #notion-article') || document.body, observerConfig ) }, 100) }) } /** * 文章内嵌广告单元 * 请在GoogleAdsense后台配置创建对应广告,并且获取相应代码 * 修改下面广告单元中的 data-ad-slot data-ad-format data-ad-layout-key(如果有) * 添加 可以在本地调试 */ const AdSlot = ({ type = 'show' }) => { const ADSENSE_GOOGLE_ID = siteConfig('ADSENSE_GOOGLE_ID') const ADSENSE_GOOGLE_TEST = siteConfig('ADSENSE_GOOGLE_TEST') if (!ADSENSE_GOOGLE_ID) { return null } // 文章内嵌广告 if (type === 'in-article') { return ( ) } // 信息流广告 if (type === 'flow') { return ( ) } // 原生广告 if (type === 'native') { return ( ) } // 展示广告 return ( ) } /** * 嵌入到文章内部的广告单元 * 检测文本内容 出现 关键词时自动替换为广告 * @param {*} props */ const AdEmbed = () => { const ADSENSE_GOOGLE_ID = siteConfig('ADSENSE_GOOGLE_ID') const ADSENSE_GOOGLE_TEST = siteConfig('ADSENSE_GOOGLE_TEST') const ADSENSE_GOOGLE_SLOT_AUTO = siteConfig('ADSENSE_GOOGLE_SLOT_AUTO') useEffect(() => { setTimeout(() => { // 找到所有 class 为 notion-text 且内容为 '' 的 div 元素 const notionTextElements = document.querySelectorAll( '#article-wrapper #notion-article div.notion-text' ) // 遍历找到的元素 notionTextElements?.forEach(element => { // 检查元素的内容是否为 '' if (element.textContent.trim() === '') { // 创建新的 元素 const newInsElement = document.createElement('ins') newInsElement.className = 'adsbygoogle w-full py-1' newInsElement.style.display = 'block' newInsElement.setAttribute('data-ad-client', ADSENSE_GOOGLE_ID) newInsElement.setAttribute( 'data-adtest', ADSENSE_GOOGLE_TEST ? 'on' : 'off' ) newInsElement.setAttribute('data-ad-slot', ADSENSE_GOOGLE_SLOT_AUTO) newInsElement.setAttribute('data-ad-format', 'auto') newInsElement.setAttribute('data-full-width-responsive', 'true') // 用新创建的 元素替换掉原来的 div 元素 element?.parentNode?.replaceChild(newInsElement, element) } }) }, 1000) }, []) return <> } export { AdEmbed, AdSlot }