import { EventName } from './eventDefs'; import { track } from '@/plugins/tracker'; export interface AdImpressionType { page_key?: string; page_name?: string; ad_type?: string; } export function setAdImpression( El: HTMLElement, advList: Types.App.AdsInfoListItem[], impression: AdImpressionType, batchType?: string, ) { // 已曝光去重(避免同广告组件重复上报) let hasReported = false; // 监听广告是否在可视区域在进行上报 const setupObserver = () => { if (!El) return; const newObserver = new IntersectionObserver( (entries) => { const entry = entries[0]; if (entry.isIntersecting && !hasReported) { triggerReport(); newObserver.disconnect(); } }, { threshold: 0.3 }, ); // 首次加载已在可视区域上报一次 requestAnimationFrame(() => { // vat-tabs类型验证是否进行首屏上报,其余检测均首屏上报 if (!isInActiveTab()) return; const rect = El.getBoundingClientRect(); const inView = rect.top < window.innerHeight * 0.7 && rect.bottom > window.innerHeight * 0.3; if (inView && !hasReported) { triggerReport(); newObserver.disconnect(); } }); newObserver.observe(El); }; const isInActiveTab = () => { let currentPane = El.closest('.van-tabs__content'); if (!currentPane) return true; // 不在 tabs 中,允许直接上报 // 从广告所在的这一层开始,一层一层往上判断 while (currentPane) { const tabs = currentPane.closest('.van-tabs') as Element; if (!tabs) break; // 到顶层 tabs 了 // 找本层 tabs 的 nav const nav = tabs.querySelector(':scope > .van-tabs__wrap > .van-tabs__nav'); if (!nav) return true; // 没有 nav,说明这层不是使用的可切换 tab // 获取本层所有 tab const tabList = Array.from(nav.querySelectorAll('.van-tab')); // 找本层选中 tab const activeTab = tabList.find((tab) => tab.getAttribute('aria-selected') === 'true'); if (!activeTab) return false; const activeId = activeTab.getAttribute('aria-controls'); if (!activeId) return false; // 在当前 tabs-content 下找对应的 swipe-item const swipeItems = Array.from( tabs.querySelectorAll(':scope > .van-tabs__content > .van-swipe > .van-swipe__track > .van-swipe-item'), ); const matchedItem = swipeItems.find((item) => item.id === activeId); if (!matchedItem) return false; // 判断 active swipe-item 是否是当前可见项 if (matchedItem.getAttribute('aria-hidden') === 'true') { return false; // 未显示,不首屏上报 } // 判断广告是否属于这一层选中的 tab 范围内 // 当前广告所在 pane 必须在 matchedItem 里面 if (!matchedItem.contains(El)) { return false; } // 下一层:往上继续递归检测 currentPane = tabs.closest('.van-tabs__content'); } return true; // 所有层都 valid,允许上报 }; //广告展示页面埋点 const triggerReport = () => { hasReported = true; if (advList.length) { const adIds = advList.map((i) => i.id).join(','); if (batchType == 'payload') { track([ { event: EventName.AdImpression, ad_slot_key: String(advList[0].position), ad_slot_name: advList[0].positionName, ad_id: adIds, creative_id: '', page_key: impression.page_key, page_name: impression.page_name, ad_type: impression.ad_type, }, ]); } else { track({ event: EventName.AdImpression, ad_slot_key: String(advList[0].position), ad_slot_name: advList[0].positionName, ad_id: adIds, creative_id: '', page_key: impression.page_key, page_name: impression.page_name, ad_type: impression.ad_type, }); } } }; return { setupObserver, }; }