130 lines
4.0 KiB
TypeScript
130 lines
4.0 KiB
TypeScript
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,
|
|
};
|
|
}
|