@ked3/ktrace
Version:
跨平台埋点分析SDK
169 lines (140 loc) • 4.32 kB
text/typescript
import Tracker from "../core/Tracker";
import { TrackerConfig, EventKey } from "../core/types";
/**
* HTML原生项目适配器类
*/
class HtmlAdapter extends Tracker {
/**
* 构造函数
*/
constructor(config: TrackerConfig) {
super(config);
}
/**
* 初始化适配器
*/
public init(): void {
if (typeof window === "undefined") {
console.warn("[KTrace] HtmlAdapter 只能在浏览器环境中使用");
return;
}
const conf = this.getConfig();
console.log('conf',conf);
// 自动添加点击追踪
if (this.getConfig().enable_auto_track) {
this.setupAutoTracking();
}
// 设置错误监听
this.setupErrorHandling();
if (this.getConfig().debug) {
console.log("[KTrace] HTML适配器初始化成功");
}
}
/**
* 设置自动追踪
*/
private setupAutoTracking(): void {
// 追踪页面访问
window.addEventListener("load", () => {
this.trackPageView();
});
// 追踪页面离开
window.addEventListener("beforeunload", () => {
this.trackEvent(EventKey.PAGE_LEAVE, {
duration: Date.now() - (window as any).__pageLoadTime || 0,
});
});
// 记录页面加载时间
(window as any).__pageLoadTime = Date.now();
// 设置路由追踪
this.setupRouteTracking();
}
/**
* 追踪页面浏览
*/
public trackPageView(path?: string): void {
const currentPath = path || window.location.pathname;
try {
this.trackEvent(EventKey.PAGE_VIEW, {
path: currentPath,
referrer: document.referrer,
user_agent: navigator.userAgent,
timestamp: Date.now()
});
} catch (error) {
if (this.getConfig().debug) {
console.warn(`[KTrace] 页面浏览追踪失败:`, error);
}
}
}
/**
* 设置路由追踪(支持SPA应用)
*/
private setupRouteTracking(): void {
// 监听 popstate 事件(浏览器前进后退)
window.addEventListener('popstate', () => {
setTimeout(() => this.trackPageView(), 100);
});
// 监听 pushState 和 replaceState
const originalPushState = history.pushState;
const originalReplaceState = history.replaceState;
history.pushState = (...args) => {
originalPushState.apply(history, args);
setTimeout(() => this.trackPageView(), 100);
};
history.replaceState = (...args) => {
originalReplaceState.apply(history, args);
setTimeout(() => this.trackPageView(), 100);
};
}
/**
* 设置错误处理
*/
private setupErrorHandling(): void {
// 监听资源加载错误(图片、脚本、样式表等)
window.addEventListener(
"error",
(event) => {
// 检查是否是资源加载错误
if (event.target && event.target !== window) {
const target = event.target as HTMLElement;
const resourceUrl = (target as any).src || (target as any).href;
const resourceType = target.tagName?.toLowerCase();
this.trackError(new Error("Resource load error"), EventKey.RESOURCE_ERROR, {
target,
resourceUrl,
resourceType
});
if (this.getConfig().debug) {
console.warn(
`[KTrace] 资源加载失败: ${resourceType} - ${resourceUrl}`
);
}
} else {
// JavaScript运行时错误
this.trackError(new Error(event.message), EventKey.JAVASCRIPT_ERROR, {
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
context: 'global'
});
if (this.getConfig().debug) {
console.warn(`[KTrace] JavaScript错误: ${event.message}`);
}
}
},
true
); // 使用捕获阶段来确保能捕获到资源错误
// 监听未处理的Promise错误
window.addEventListener("unhandledrejection", (event) => {
this.trackError(new Error(event.reason), EventKey.CUSTOM_ERROR, {
error_type: 'unhandled_promise_rejection',
context: 'global'
});
if (this.getConfig().debug) {
console.warn(`[KTrace] 未处理的Promise错误:`, event.reason);
}
});
}
}
export default HtmlAdapter;