import { App } from 'vue'; import { Router } from 'vue-router'; import { BehaviorReporter } from '@tencent/merlin-behavior'; import { WebBehaviorCollector, WebBehaviorCollectorOptions } from '@tencent/merlin-behavior-web'; import { registerExposeTargetHook } from './hooks/ml-expose'; import { registerExposeRootHook } from './hooks/ml-exposeRoot'; import { registerVideoHook } from './hooks/ml-video'; import { isAllRouteHaveName } from './utils'; import { registerClickHook } from './hooks/ml-click'; import { registerHoverHook } from './hooks/ml-hover'; export interface VueBehaviorCollectorOptions extends WebBehaviorCollectorOptions { app: App; router?: Router; } export class VueBehaviorCollector extends WebBehaviorCollector { private app: App; private router?: Router; private routerDepth = 0; constructor(options: VueBehaviorCollectorOptions) { super(options); this.app = options.app; this.router = options.router; } init(reporter: BehaviorReporter) { super.init(reporter); registerExposeTargetHook(this.app, this); registerExposeRootHook(this.app, this); this.kickStartExpose(); registerVideoHook(this.app, this); registerClickHook(this.app, this); registerHoverHook(this.app, this); this.registerPage(); } destroy() { super.destroy(); } private registerPage() { if (!this.router) { return; } if (!isAllRouteHaveName(this.router)) { throw Error('every route in Vue-router must have a name'); } this.router.afterEach((to, from) => { const currentTime = new Date().getTime(); let enterTime = currentTime; try { sessionStorage.setItem(to.name as string, currentTime.toString()); if (from?.name) { const storageItem = parseFloat(sessionStorage.getItem(from.name as string) || ''); if (!Number.isNaN(storageItem)) { enterTime = storageItem; } } } catch { // 隐私模式下 iframe 访问 storage 会被拦截 } const stayTime = currentTime - enterTime; const prevPage = this.reporter?.loadPage(); if (prevPage) { this.reporter?.reportPageLeave({ stayTime, // extInfo: {...from.params, ...from.query } }); } const eleId = Array.isArray(to.query.from_element_id) ? to.query.from_element_id[0] : to.query.from_element_id; const ml = to.meta?.ml as null | { pageId: string; extInfo: any; }; const pageInfo = { name: ml?.pageId ?? (to.name as string), extInfo: { ...to.params, ...to.query, ...ml?.extInfo, }, }; this.reporter?.pushPage(pageInfo, eleId ?? ''); this.routerDepth = this.routerDepth + 1; this.reporter?.reportPageEnter({}); }); } }