核心是用 class 封装日志埋点,通过基类 Tracker 统一采集与上报,AutoTracker 装饰器实现自动埋点,Page/Click/ApiTracker 按场景继承扩展,并支持多实例隔离,使埋点工程化、可复用、可配置。

用 class 封装日志埋点,核心是把“采集逻辑”和“上报行为”抽离成可复用、可配置、可继承的结构,避免每个业务方法里重复写 logEvent 或手动拼参数。
定义基础埋点类(统一采集与发送)
创建一个基类,负责管理事件名、属性、时间戳、用户 ID 等通用字段,并提供标准上报方法:
class Tracker {
constructor(options = {}) {
this.appId = options.appId || 'web';
this.env = options.env || 'prod';
this.userId = options.userId || this.getUserId();
this.sessionId = this.generateSessionId();
}
<p>getUserId() {
return localStorage.getItem('uid') || 'anonymous';
}</p><p>generateSessionId() {
return sessionStorage.getItem('session_id') ||
(Math.random().toString(36).substr(2, 9) + Date.now()).slice(-12);
}</p><p>// 标准化日志对象
buildLog(event, props = {}) {
return {
event,
props: {
...props,
appId: this.appId,
env: this.env,
userId: this.userId,
sessionId: this.sessionId,
timestamp: Date.now(),
}
};
}</p><p>// 上报(可替换为 sendBeacon / fetch / image ping)
send(log) {
if (navigator.sendBeacon) {
navigator.sendBeacon('/log', JSON.stringify(log));
} else {
fetch('/log', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(log),
keepalive: true
});
}
}</p><p>// 主动触发埋点
track(event, props = {}) {
const log = this.buildLog(event, props);
this.send(log);
}
}</p>用装饰器或方法代理自动埋点(减少侵入)
不希望每个函数都手动调用 track?可以封装一个装饰器类,对目标方法做增强:
${eventName}_start按场景派生专用埋点类(如页面、按钮、接口)
针对高频场景,继承 Tracker,预设事件类型和字段规则:
-
PageTracker:自动记录 PV、停留时长、来源页;监听
visibilitychange和beforeunload - ClickTracker:绑定事件委托,根据 data-track 属性识别可埋点按钮,提取 text / id / position
- ApiTracker:配合 Axios/Fetch 拦截器,在请求发起和响应后分别打点,带 status、duration、url path
例如 ClickTracker 简化版:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
class ClickTracker extends Tracker {
constructor(options) {
super(options);
this.init();
}
<p>init() {
document.addEventListener('click', (e) => {
const el = e.target.closest('[data-track]');
if (!el) return;</p><pre class="brush:php;toolbar:false;"> const name = el.dataset.track;
const props = {
tagName: el.tagName.toLowerCase(),
text: el.innerText?.trim().slice(0, 50) || '',
id: el.id || '',
className: el.className || '',
x: e.clientX,
y: e.clientY
};
this.track(`click_${name}`, props);
}, true);} }
new ClickTracker({ appId: 'shop', userId: getUserID() }); // 全局启用
支持异步加载与多实例隔离
大型项目常需多个埋点通道(如 A/B 实验分开上报、错误日志走独立 endpoint),可用工厂模式生成隔离实例:
class TrackerFactory {
static create(config) {
const instance = new Tracker(config);
<pre class="brush:php;toolbar:false;">// 隔离上报地址
instance.send = function(log) {
const url = config.endpoint || '/log';
fetch(url, {
method: 'POST',
body: JSON.stringify(log),
headers: { 'Content-Type': 'application/json' }
});
};
return instance;} }
// 不同用途不同实例 const analyticsTracker = TrackerFactory.create({ appId: 'web', endpoint: '/v1/analytics' });
const errorTracker = TrackerFactory.create({ appId: 'web', endpoint: '/v1/errors', env: 'prod' });
这样封装后,埋点不再是散落在各处的 console.log 式调用,而是具备生命周期管理、错误兜底、环境适配和扩展能力的模块。关键不是“用 class”,而是借 class 的封装性把日志逻辑真正工程化。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










