思维决定AI代码质量-基于业务设计思想与AI编程的结果

17 阅读17分钟

📊 Tracker - 事件与数据追踪系统

一个轻量级、类型安全的 React 事件与数据追踪框架,支持 DOM 事件自动追踪、React 状态监听和自定义追踪器。

✨ 特性

  • 🎯 类型安全 - 完整的 TypeScript 类型支持
  • 🔄 消息中心 - 统一的消息管理和分发机制
  • 🖱️ 自动 DOM 追踪 - 自动监听 DOM 事件(点击、悬停等)
  • 📦 状态追踪 - React useState 状态变更自动追踪
  • 🎨 高度可定制 - 支持自定义追踪器和数据提取
  • 性能优化 - 防抖、节流、采样率控制
  • 🪝 React Hooks - 开箱即用的 React Hooks
  • 🔌 非侵入式 - 不影响原有业务逻辑

📦 安装

npm install light-web-track
# 或
yarn add light-web-track
# 或
pnpm add light-web-track

📖 使用

// 导出追踪器类
import { TrackerClass, EventTracker, DataTracker, UserTracker } from 'light-web-track';

// 导出消息中心
import { TrackerMessageCenter, messageCenter } from 'light-web-track';

// 导出追踪器类型
import { TrackerType } from 'light-web-track';

// 导出 DOM 事件追踪器
import { DOMEventTracker, ClickTracker, HoverTracker } from 'light-web-track';

// 导出 React 状态追踪
import { 
  ProxyDataTracker, 
  useTrackedState, 
  useTrackedObjectState, 
  createTrackedStateHook 
} from 'light-web-track';

// 导出 React Hooks
import { 
  useDOMEventTracker,
  useClickTracker,
  useHoverTracker,
  useCustomTracker
} from 'light-web-track';

🚀 快速开始

1. 初始化消息中心

在应用入口文件中注册消息处理器:

import { messageCenter, TrackerType } from 'light-web-track';

// 注册消息处理器
function setupTrackerHandlers() {
  // 处理事件追踪消息(DOM 点击、悬停等)
  messageCenter.on(TrackerType.Event, async (message) => {
    console.log('Event:', message);
    // 发送到分析平台,如 Google Analytics
    // await sendToAnalytics(message);
  });

  // 处理数据追踪消息(状态变更等)
  messageCenter.on(TrackerType.Data, async (message) => {
    console.log('Data:', message);
    // 发送到数据仓库
    // await sendToDataWarehouse(message);
  });

  // 全局处理器(接收所有类型的消息)
  messageCenter.onAll(async (message) => {
    console.log('All:', message.type, message.timestamp);
    // 统一日志记录
    // await logToServer(message);
  });
}

// 在应用启动时调用
setupTrackerHandlers();

2. DOM 事件追踪

使用 Hook(推荐)
// 方式 1: 使用简化的 useClickTracker
import { useClickTracker } from 'light-web-track';

function MyComponent() {
  // 自动追踪所有按钮点击
  useClickTracker();

  return (
    <div>
      <button>点击我</button>
    </div>
  );
}

// 方式 2: 使用通用的 useDOMEventTracker
import { useDOMEventTracker } from 'light-web-track';

function MyComponent() {
  useDOMEventTracker({
    eventTypes: ['click'],
    selector: 'button',
  });

  return (
    <div>
      <button>点击我</button>
    </div>
  );
}
使用追踪器类
import { ClickTracker, HoverTracker } from 'light-web-track';

// 全局点击追踪
const clickTracker = new ClickTracker({
  selector: 'button, a, [data-track]',
  samplingRate: 1.0, // 100% 采样
});
await clickTracker.start();

// 悬停追踪(带防抖)
const hoverTracker = new HoverTracker({
  selector: '.card',
  debounceDelay: 300, // 300ms 防抖
});
await hoverTracker.start();

3. React 状态追踪

import { useTrackedState } from 'light-web-track';

function Counter() {
  // 自动追踪 count 状态变更
  const [count, setCount] = useTrackedState(0, {
    stateKey: 'count',
    componentName: 'Counter',
  });

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}

4. 对象状态追踪

import { useTrackedObjectState } from 'light-web-track';

function UserForm() {
  const [user, setUser] = useTrackedObjectState(
    { name: '', age: 0 },
    {
      stateKey: 'user',
      componentName: 'UserForm',
      trackFields: ['name', 'age'], // 只追踪这些字段
    }
  );

  return (
    <div>
      <input
        value={user.name}
        onChange={(e) => setUser({ ...user, name: e.target.value })}
      />
      <input
        type="number"
        value={user.age}
        onChange={(e) => setUser({ ...user, age: Number(e.target.value) })}
      />
    </div>
  );
}

🏗️ 核心概念

系统架构

Tracker 采用生产者-消费者架构:

┌─────────────────────────────────────────────────────────────┐
│                     追踪器 (Producer)                        │
│  ┌──────────────────────────────────────────────────────┐   │
│  │  1. beforeTracking()   - 条件判断、数据验证         │   │
│  │  2. trackingHandler()  - 发送消息到消息中心        │   │
│  │  3. afterTracking()    - 清理、统计、通知         │   │
│  │  4. onTrackingError()  - 错误处理                  │   │
│  └──────────────────────────────────────────────────────┘   │
└────────────────────┬────────────────────────────────────────┘
                     │ 发送消息 (TrackerMessage)
┌────────────────────▼────────────────────────────────────────┐
│          消息中心 (TrackerMessageCenter)                    │
│  负责消息的分发到注册的处理器                              │
└────────────────────┬────────────────────────────────────────┘
                     │ 分发消息
┌────────────────────▼────────────────────────────────────────┐
│             消息处理器 (Consumer)                           │
│  ┌──────────────────┐  ┌──────────────────┐               │
│  │  事件处理器      │  │  数据处理器      │               │
│  │  上报到分析平台  │  │  存储到数据库    │               │
│  └──────────────────┘  └──────────────────┘               │
│  ┌──────────────────┐  ┌──────────────────┐               │
│  │  性能监控器      │  │  错误监控器      │               │
│  │  分析性能指标    │  │  收集错误信息    │               │
│  └──────────────────┘  └──────────────────┘               │
└─────────────────────────────────────────────────────────────┘

TrackerClass 生命周期

每个追踪器的执行流程:

┌────────────────────────────────────────┐
│  tracker.run(runtimePayload?)          │
└────────────────┬───────────────────────┘
                 │
                 ▼
        ┌────────────────────┐
        │ beforeTracking()   │  ◄─── 返回 false 则停止
        │ 条件判断/验证      │
        └────────┬───────────┘
                 │
                 ▼
        ┌────────────────────┐
        │ trackingHandler()  │  ◄─── 发送消息
        │ 核心业务逻辑       │
        └────────┬───────────┘
                 │
        ┌────────▼────────┐
        │   成功 or 异常  │
        └────────┬─────┬──┘
                 │     │
         (成功)  │     │  (异常)
                 ▼     ▼
        ┌──────────────┐  ┌──────────────────┐
        │afterTracking │  │ onTrackingError()│
        │清理/统计/通知│  │  错误处理        │
        └──────────────┘  └──────────────────┘

消息中心 (TrackerMessageCenter)

消息中心是整个追踪系统的核心,负责消息的发送、接收和分发。

import { messageCenter, TrackerType } from 'light-web-track';

// 发送消息
await messageCenter.send(TrackerType.Event, {
  eventType: 'click',
  target: 'button',
});

// 注册处理器
const handler = async (message) => {
  console.log(message);
};
messageCenter.on(TrackerType.Event, handler);

// 移除处理器
messageCenter.off(TrackerType.Event, handler);

// 清空所有处理器
messageCenter.clear();

追踪器基类 (TrackerClass)

所有追踪器都继承自 TrackerClass,提供了统一的生命周期管理。

import { TrackerClass } from 'light-web-track';

class MyTracker extends TrackerClass<MyPayload> {
  // 前置钩子:决定是否执行追踪
  protected async beforeTracking(payload: MyPayload): Promise<boolean> {
    // 自定义条件判断
    return payload.value > 0;
  }

  // 核心钩子:执行追踪逻辑
  protected async trackingHandler(payload: MyPayload): Promise<void> {
    await this.sendMessage(payload);
  }

  // 后置钩子:追踪完成后的操作
  protected async afterTracking(payload: MyPayload): Promise<void> {
    console.log('Tracked:', payload);
  }

  // 错误处理
  protected async onTrackingError(error: Error, payload: MyPayload): Promise<void> {
    console.error('Error:', error);
  }
}

追踪器类型

enum TrackerType {
  Basic = 'Base',       // 基础追踪
  Event = 'Web_Event',  // DOM 事件追踪
  Data = 'Data',        // 数据变更追踪
  User = 'User',        // 用户行为追踪
}

📚 API 文档

DOMEventTracker

自动监听 DOM 事件的追踪器。

interface DOMEventTrackerConfig {
  eventTypes: string[];                    // 事件类型数组,如 ['click', 'mouseenter']
  selector?: string;                       // CSS 选择器(默认 '*')
  samplingRate?: number;                   // 采样率 0-1(默认 1.0)
  debounceDelay?: number;                  // 防抖延迟(毫秒,默认 0)
  throttleDelay?: number;                  // 节流延迟(毫秒,默认 0)
  extractData?: (e: Event, el: HTMLElement) => any;  // 自定义数据提取
  disableAutoTrack?: boolean;              // 禁用自动追踪(默认 false)
}

方法:

  • start() - 开始追踪
  • stop() - 停止追踪
  • track(event, target) - 手动追踪单个事件

内置追踪器:

  • ClickTracker - 点击事件追踪器(eventTypes: ['click']
  • HoverTracker - 悬停事件追踪器(eventTypes: ['mouseenter']

ProxyDataTracker

React 状态追踪器,用于监听 useState 的状态变更。

interface UseStateTrackingData {
  stateKey: string;           // 状态键名
  oldValue: any;              // 旧值
  newValue: any;              // 新值
  componentName?: string;     // 组件名称
  timestamp?: number;         // 时间戳
}

React Hooks

useDOMEventTracker

通用的 DOM 事件追踪 Hook。

function useDOMEventTracker(
  config: DOMEventTrackerConfig,
  deps?: DependencyList
): DOMEventTracker | null;
useClickTracker

简化的点击追踪 Hook,预配置了点击事件。

function useClickTracker(
  selector?: string,      // CSS 选择器(默认 'button, a, [data-track-click]')
  samplingRate?: number   // 采样率 0-1(默认 1.0)
): ClickTracker | null;

// 使用示例
useClickTracker();                    // 使用默认配置
useClickTracker('.custom-button');    // 自定义选择器
useClickTracker('button', 0.5);       // 50% 采样率
useHoverTracker

简化的悬停追踪 Hook,预配置了鼠标悬停事件。

function useHoverTracker(
  selector?: string,        // CSS 选择器(默认 '[data-track-hover]')
  throttleDelay?: number    // 节流延迟(默认 500ms)
): HoverTracker | null;

// 使用示例
useHoverTracker();                 // 使用默认配置(500ms 节流)
useHoverTracker('.card');          // 自定义选择器
useHoverTracker('.card', 1000);    // 1 秒节流
useCustomTracker

更灵活的自定义追踪 Hook,支持完整的配置选项。

function useCustomTracker(
  options: DOMEventTrackerConfig
): DOMEventTracker | null;

// 使用示例
useCustomTracker({
  eventTypes: ['click', 'dblclick', 'contextmenu'],
  selector: '.interactive-element',
  samplingRate: 0.8,
  extractData: (event, element) => ({
    elementId: element.id,
    timestamp: Date.now(),
  }),
});
useTrackedState
function useTrackedState<T>(
  initialValue: T,
  options: TrackingOptions
): [T, React.Dispatch<React.SetStateAction<T>>];

interface TrackingOptions {
  stateKey: string;
  componentName?: string;
  disableTracking?: boolean;
}
useTrackedObjectState
function useTrackedObjectState<T extends Record<string, any>>(
  initialValue: T,
  options: ObjectTrackingOptions
): [T, React.Dispatch<React.SetStateAction<T>>];

interface ObjectTrackingOptions extends TrackingOptions {
  trackFields?: (keyof T)[];  // 指定要追踪的字段
}
createTrackedStateHook

创建自定义的状态追踪 Hook。

function createTrackedStateHook<T>(
  defaultOptions: Partial<TrackingOptions>
): (
  initialValue: T,
  options?: Partial<TrackingOptions>
) => [T, React.Dispatch<React.SetStateAction<T>>];

🎯 使用场景

1. 用户行为分析

// 追踪所有交互元素
useDOMEventTracker({
  eventTypes: ['click', 'mouseenter'],
  selector: 'button, a, [role="button"]',
});

2. 表单输入监控

const [formData, setFormData] = useTrackedObjectState(
  { email: '', password: '' },
  {
    stateKey: 'loginForm',
    componentName: 'LoginPage',
  }
);

3. 性能监控

class PerformanceTracker extends TrackerClass<PerformanceData> {
  constructor() {
    super(TrackerType.Basic, {} as PerformanceData);
  }

  async measurePageLoad() {
    const navigationTiming = performance.getEntriesByType('navigation')[0];
    await this.run({
      loadTime: navigationTiming.duration,
      domContentLoaded: navigationTiming.domContentLoadedEventEnd,
      // ... 更多性能指标
    });
  }
}

4. 自定义事件追踪

class CustomTracker extends EventTracker {
  async trackCustomEvent(eventName: string, data: any) {
    await this.run({
      eventType: 'custom',
      eventName,
      data,
      timestamp: Date.now(),
    });
  }
}

⚡ 性能优化

防抖 (Debounce)

延迟执行,适用于搜索输入等高频事件。

useDOMEventTracker({
  eventTypes: ['input'],
  selector: 'input[type="search"]',
  debounceDelay: 500, // 500ms 后执行
});

节流 (Throttle)

限制执行频率,适用于滚动、鼠标移动等。

useDOMEventTracker({
  eventTypes: ['mousemove'],
  selector: '.interactive-canvas',
  throttleDelay: 100, // 每 100ms 最多执行一次
});

采样率控制

减少追踪数据量,适用于高流量场景。

useDOMEventTracker({
  eventTypes: ['click'],
  selector: '*',
  samplingRate: 0.1, // 只追踪 10% 的事件
});

🔧 扩展指南

扩展追踪器类型

创建追踪器很简单,只需继承 TrackerClass 并实现三个生命周期钩子。

步骤 1:定义 Payload 类型
// 在 typing.d.ts 中添加
declare namespace Tracker {
  interface CustomTrackerPayload {
    action: string;
    value: number;
    metadata?: Record<string, any>;
  }
}
步骤 2:创建追踪器类
// 创建文件:CustomTracker.ts
import { TrackerClass } from './TrackerClass';
import { TrackerType } from './constant';

class CustomTracker extends TrackerClass<Tracker.CustomTrackerPayload> {
  constructor() {
    super(TrackerType.Basic, { action: '', value: 0 });
  }

  /**
   * 前置钩子:决定什么时候触发
   * 用于条件判断、数据验证、采样控制等
   */
  protected async beforeTracking(payload: Tracker.CustomTrackerPayload): Promise<boolean> {
    // 示例:只追踪 value > 0 的情况
    if (payload.value <= 0) {
      console.log('[CustomTracker] value 不符合条件,跳过追踪');
      return false;
    }

    // 示例:采样控制
    if (Math.random() > 0.8) {
      // 只追踪 80% 的事件
      return false;
    }

    return true;
  }

  /**
   * 核心钩子:决定触发时做什么
   * 通常是发送消息到消息中心,并可进行数据转换
   */
  protected async trackingHandler(payload: Tracker.CustomTrackerPayload): Promise<void> {
    // 数据转换或增强
    const enrichedData = {
      ...payload,
      timestamp: Date.now(),
      userAgent: navigator.userAgent,
    };

    // 发送到消息中心
    await this.sendMessage(enrichedData, { source: 'custom-tracker' });
  }

  /**
   * 后置钩子:决定触发后做什么
   * 用于清理、统计、日志等
   */
  protected async afterTracking(payload: Tracker.CustomTrackerPayload): Promise<void> {
    console.log('[CustomTracker] 追踪完成:', payload.action);
    // 可以在这里更新本地统计、触发后续流程等
  }

  // 可选:覆盖错误处理
  protected async onTrackingError(
    error: Error,
    payload: Tracker.CustomTrackerPayload
  ): Promise<void> {
    console.error('[CustomTracker] 追踪失败:', {
      action: payload.action,
      error: error.message,
    });
    // 可以上报到错误监控系统
  }
}

export { CustomTracker };
步骤 3:使用追踪器
// 方式 1:使用静态 payload(构造时确定)
const tracker = new CustomTracker();
await tracker.run({ action: 'search', value: 100 });

// 方式 2:使用动态 payload(运行时传入)
const tracker = new CustomTracker();
const userAction = getUserAction();
await tracker.run(userAction);

新增追踪器类型

如果需要系统中新的追踪器类型,有两种方式:

方式 1:新增枚举值(推荐)
// 在 constant.ts 中
export enum TrackerType {
  Basic = 'Base',
  Event = 'Web_Event',
  Data = 'Data',
  User = 'User',
  Custom = 'Custom',        // 新增
  Performance = 'Performance' // 新增
}

然后创建对应的追踪器类:

class CustomTracker extends TrackerClass<CustomPayload> {
  constructor(payload: CustomPayload) {
    super(TrackerType.Custom, payload);
  }
  // ... 实现生命周期钩子
}

class PerformanceTracker extends TrackerClass<PerformancePayload> {
  constructor(payload: PerformancePayload) {
    super(TrackerType.Performance, payload);
  }
  // ... 实现生命周期钩子
}
方式 2:使用现有类型扩展

如果不想新增枚举值,可以用现有类型:

class CustomTracker extends EventTracker<CustomPayload> {
  constructor(payload: CustomPayload) {
    super(payload, TrackerType.Event); // 复用 Event 类型
  }
  // ... 自定义实现
}

创建 React Hook 追踪器

如果需要在 React 组件中使用自定义追踪器,可以创建 Hook:

// 在 useTracker.ts 中添加
import { useEffect } from 'react';
import { CustomTracker } from './CustomTracker';

function useCustomTracker(action: string, value: number) {
  useEffect(() => {
    const tracker = new CustomTracker();
    
    // 异步执行追踪,不阻塞渲染
    tracker.run({ action, value }).catch(err => {
      console.error('Tracker error:', err);
    });

    // 清理(虽然追踪器不需要清理,但这是好的实践)
    return () => {
      // 可选:如果追踪器有清理逻辑,在这里调用
    };
  }, [action, value]);
}

export { useCustomTracker };

注册消息处理器

新增的追踪器类型需要在初始化时注册对应的消息处理器:

// 在应用入口(通常是 main.tsx)
import { messageCenter, TrackerType } from 'light-web-track';
import { setupTrackerHandlers } from 'light-web-track';

function setupCustomTrackerHandlers() {
  // 处理自定义追踪消息
  messageCenter.on(TrackerType.Custom, async (message) => {
    console.log('Custom tracker message:', message);
    
    // 发送到后端或分析平台
    // await sendToBackend(message);
  });

  // 处理性能追踪消息
  messageCenter.on(TrackerType.Performance, async (message) => {
    console.log('Performance tracker message:', message);
    
    // 发送到性能监控系统
    // await sendToMonitoringSystem(message);
  });
}

// 应用启动时调用
setupTrackerHandlers();
setupCustomTrackerHandlers();

完整扩展示例:用户行为追踪器

以下是一个完整的扩展示例,展示如何创建用户行为追踪器:

// 定义类型
declare namespace Tracker {
  interface UserActionPayload {
    userId: string;
    action: 'login' | 'logout' | 'signup' | 'purchase';
    details?: Record<string, any>;
  }
}

// 创建追踪器
class UserActionTracker extends TrackerClass<Tracker.UserActionPayload> {
  constructor() {
    super(TrackerType.User, { userId: '', action: 'login' });
  }

  protected async beforeTracking(payload: Tracker.UserActionPayload): Promise<boolean> {
    // 检查用户 ID 是否存在
    if (!payload.userId) {
      console.warn('[UserActionTracker] 用户 ID 为空,跳过追踪');
      return false;
    }

    // 检查用户是否同意数据收集
    const hasConsent = await this.checkUserConsent(payload.userId);
    return hasConsent;
  }

  protected async trackingHandler(payload: Tracker.UserActionPayload): Promise<void> {
    const enrichedData = {
      ...payload,
      timestamp: Date.now(),
      sessionId: this.getSessionId(),
      source: 'user-action-tracker',
    };

    await this.sendMessage(enrichedData);
  }

  protected async afterTracking(payload: Tracker.UserActionPayload): Promise<void> {
    // 记录追踪成功
    console.log(`[UserActionTracker] 用户 ${payload.userId}${payload.action} 已追踪`);
  }

  private async checkUserConsent(userId: string): Promise<boolean> {
    // 实现用户同意逻辑
    return true; // 简化示例
  }

  private getSessionId(): string {
    // 获取或生成 Session ID
    return sessionStorage.getItem('sessionId') || this.generateSessionId();
  }

  private generateSessionId(): string {
    const sessionId = Math.random().toString(36).substring(7);
    sessionStorage.setItem('sessionId', sessionId);
    return sessionId;
  }
}

// 创建对应的 React Hook
function useUserActionTracker(userId: string) {
  return {
    trackAction: async (action: 'login' | 'logout' | 'signup' | 'purchase', details?: any) => {
      const tracker = new UserActionTracker();
      await tracker.run({ userId, action, details });
    },
  };
}

// 在组件中使用
function LoginPage() {
  const { trackAction } = useUserActionTracker('user123');

  const handleLogin = async () => {
    // 登录逻辑...
    await trackAction('login', { method: 'password' });
  };

  return <button onClick={handleLogin}>登录</button>;
}

// 注册消息处理器
messageCenter.on(TrackerType.User, async (message) => {
  const payload = message.payload as Tracker.UserActionPayload;
  // 发送到后端
  await fetch('/api/track/user-action', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });
});

扩展清单

创建新的追踪器时,请确保完成以下步骤:

  • typing.d.ts 中定义 Payload 类型
  • 创建追踪器类文件(或在现有文件中添加)
  • 实现三个生命周期钩子:beforeTrackingtrackingHandlerafterTracking
  • 可选:实现 onTrackingError 错误处理
  • 如果需要新的追踪器类型,在 constant.ts 中添加枚举值
  • index.ts 中导出新的追踪器类
  • 如果需要 React Hook,在 useTracker.ts 中创建相应 Hook
  • 在应用初始化时注册消息处理器(消息消费端)
  • 为新的追踪器类型添加单元测试(可选但推荐)
  • 更新此 README 文档,说明新追踪器的使用方式

🔧 高级配置

自定义数据提取

useDOMEventTracker({
  eventTypes: ['click'],
  selector: 'button',
  extractData: (event, element) => {
    return {
      buttonText: element.textContent,
      buttonId: element.id,
      userAgent: navigator.userAgent,
      screenWidth: window.innerWidth,
      // ... 任何你需要的数据
    };
  },
});

手动追踪

const tracker = useDOMEventTracker({
  eventTypes: ['click'],
  selector: 'button',
  disableAutoTrack: true, // 禁用自动追踪
});

const handleClick = (e: MouseEvent) => {
  if (shouldTrack(e)) {
    tracker?.track(e, e.target as HTMLElement);
  }
};

条件追踪

class ConditionalTracker extends EventTracker {
  protected async beforeTracking(payload: any): Promise<boolean> {
    // 只追踪登录用户
    const isLoggedIn = await checkUserLogin();
    if (!isLoggedIn) {
      return false;
    }

    // 采样控制
    if (Math.random() > 0.5) {
      return false;
    }

    return true;
  }
}

⚠️ 常见问题与注意事项

Hook 导出问题

当前所有 Hooks 已在 index.ts 中导出,可以直接导入:

// ✅ 正确的导入方式
import { useClickTracker } from 'light-web-track';

追踪器类型值

实际的 TrackerType 枚举值:

TrackerType.Basic = 'Base'
TrackerType.Event = 'Web_Event'
TrackerType.Data = 'Data'
TrackerType.User = 'User'

生命周期钩子返回值

// beforeTracking() 返回值说明
return false;        // 跳过追踪
return true;         // 继续执行
return undefined;    // 等同于 true,继续执行
return Promise<...>  // 支持异步,结果转为布尔值

// trackingHandler() 返回值说明
// 无需返回值,但支持异步执行

// afterTracking() 返回值说明
// 无需返回值,但支持异步执行

// onTrackingError() 返回值说明
// 无需返回值,但支持异步执行

性能考虑

  • 高频事件(如 mousemovescroll务必使用节流或防抖
  • 在生产环境中根据流量使用采样率
  • 追踪数据应异步发送,不要阻塞 UI
  • 追踪器会自动捕获错误,不会影响业务逻辑
  • 避免在 trackingHandler() 中进行 DOM 操作,会影响性能

内存管理

  • 组件卸载时追踪器会自动清理
  • 使用 Hook 方式会自动管理生命周期
  • 手动创建的追踪器需要手动调用 stop()
  • 不要创建循环引用,避免内存泄漏

数据安全

  • 不要在追踪消息中包含敏感信息(密码、密钥、个人隐私)
  • 始终检查用户是否同意数据收集
  • 遵守 GDPR、CCPA 等数据保护法规
  • beforeTracking() 中实现用户同意检查
protected async beforeTracking(payload: TPayload): Promise<boolean> {
  // 检查用户是否同意收集数据
  const hasConsent = await checkUserConsent();
  if (!hasConsent) {
    return false; // 不追踪
  }
  return true;
}

消息处理器的异常处理

消息处理器中的异常不会影响追踪器本身,但应该妥善处理:

messageCenter.on(TrackerType.Event, async (message) => {
  try {
    await sendToAnalyticsServer(message);
  } catch (error) {
    // 上报到错误监控系统,但不影响应用运行
    console.error('Failed to send tracking data:', error);
    await reportErrorToMonitoring(error);
  }
});

扩展时常见错误

1. 忘记调用 sendMessage()
// ❌ 错误:没有发送消息
protected async trackingHandler(payload: TPayload): Promise<void> {
  // 只做了数据处理,没有发送消息
  const enriched = { ...payload, timestamp: Date.now() };
  // 消息不会被消息中心处理
}

// ✅ 正确
protected async trackingHandler(payload: TPayload): Promise<void> {
  const enriched = { ...payload, timestamp: Date.now() };
  await this.sendMessage(enriched); // 必须调用
}
2. 在 beforeTracking() 中进行副作用操作
// ❌ 错误:beforeTracking 返回 false,但副作用已经发生
protected async beforeTracking(payload: TPayload): Promise<boolean> {
  await updateLocalStorage(payload); // 如果返回 false,这会是浪费操作
  return shouldTrack(payload);
}

// ✅ 正确:只进行条件判断
protected async beforeTracking(payload: TPayload): Promise<boolean> {
  // 只判断条件,不做其他操作
  return shouldTrack(payload);
}

// 副作用放在 afterTracking()
protected async afterTracking(payload: TPayload): Promise<void> {
  await updateLocalStorage(payload); // 只有追踪成功才会执行
}
3. 没有处理异步操作中的错误
// ❌ 不好的做法:async/await 中可能抛出异常
protected async trackingHandler(payload: TPayload): Promise<void> {
  const response = await fetch(SERVER, { /* ... */ });
  const data = await response.json(); // 可能会抛出异常
  await this.sendMessage(data);
}

// ✅ 最佳做法:异常已由 run() 方法处理
// 不需要额外处理,run() 会捕获所有异常并调用 onTrackingError()
protected async trackingHandler(payload: TPayload): Promise<void> {
  const response = await fetch(SERVER, { /* ... */ });
  const data = await response.json();
  await this.sendMessage(data);
  // 如果有异常,会被 run() 方法捕获
}
4. 在 React Hook 中忘记清理
// ⚠️ 组件多次渲染时会重复创建追踪器
function useMyCustomTracker() {
  const handleClick = async () => {
    const tracker = new MyTracker();
    await tracker.run(data);
  };

  return { handleClick };
}

// ✅ 正确做法:缓存追踪器实例
function useMyCustomTracker() {
  const trackerRef = useRef<MyTracker | null>(null);

  if (!trackerRef.current) {
    trackerRef.current = new MyTracker();
  }

  const handleClick = async (data: TPayload) => {
    await trackerRef.current!.run(data);
  };

  return { handleClick };
}

调试技巧

1. 启用详细日志

所有追踪器都会在控制台输出日志:

// 追踪器会输出这样的日志:
// [Tracker] beforeTracking 返回 false,跳过追踪
// [EventTracker] 准备追踪事件: {...}
// [EventTracker] 事件追踪完成
2. 监听所有消息
messageCenter.onAll((message) => {
  console.log('All tracking messages:', message);
});

调试技巧

1. 启用详细日志

所有追踪器都会在控制台输出日志:

// 追踪器会输出这样的日志:
// [Tracker] beforeTracking 返回 false,跳过追踪
// [EventTracker] 准备追踪事件: {...}
// [EventTracker] 事件追踪完成
2. 监听所有消息
messageCenter.onAll((message) => {
  console.log('All tracking messages:', message);
});
3. 测试 beforeTracking() 条件
const tracker = new MyTracker();

// 直接调用钩子来测试条件
const shouldTrack = await tracker['beforeTracking']({ /* payload */ });
console.log('Should track:', shouldTrack);

📁 项目文件结构说明

src/
├── index.ts                      # 统一导出入口
├── core/                         # 核心模块
│   ├── constant.ts              # 追踪器类型和常量定义
│   ├── TrackerClass.ts          # 追踪器基类和实现类
│   └── TrackerMessageCenter.ts   # 消息中心实现
├── trackers/                     # 追踪器实现
│   ├── DOMEventTracker.ts        # DOM 事件追踪器
│   └── ProxyDataTracker.ts       # React 状态追踪器
├── hooks/                        # React Hooks
│   └── useTracker.ts            # 追踪器 Hooks
├── types/                        # 类型定义
│   └── typing.d.ts              # 全局类型定义
└── README.md                     # 文档

文件职责

文件职责
core/constant.ts定义追踪器类型枚举和业务常量
core/TrackerClass.ts实现追踪器基类和生命周期管理
core/TrackerMessageCenter.ts实现消息中心和分发机制
trackers/DOMEventTracker.ts实现 DOM 事件追踪器
trackers/ProxyDataTracker.ts实现 React 状态追踪器
hooks/useTracker.ts实现 React Hooks(生产者端)
types/typing.d.ts全局类型定义(Tracker 命名空间)
index.ts统一导出公共 API

添加新追踪器的文件修改清单

如果需要添加新的追踪器,需要修改以下文件:

1. constant.ts(可选)

如果需要新的追踪器类型,添加枚举值:

export enum TrackerType {
  // 现有类型...
  MyCustom = 'My_Custom'  // ← 添加新类型
}
2. typing.d.ts

添加新 Payload 类型定义:

declare namespace Tracker {
  interface MyCustomPayload {
    // 你的属性定义
  }
}
3. 新建文件或在现有文件添加追踪器类

创建追踪器类或扩展现有类:

export class MyCustomTracker extends TrackerClass<Tracker.MyCustomPayload> {
  // 实现...
}
4. useTracker.ts(可选)

如果需要 React Hook,添加对应的 Hook:

export function useMyCustomTracker(options?: any) {
  // 实现...
}
5. index.ts

导出新的追踪器和 Hook:

export { MyCustomTracker } from './YourFile';
export { useMyCustomTracker } from './useTracker';
6. 应用初始化

在应用启动时注册消息处理器:

messageCenter.on(TrackerType.MyCustom, async (message) => {
  // 处理消息
});

✅ 扩展检查表

创建新追踪器时,请按以下步骤检查:

设计阶段

  • 确定追踪器名称和类型
  • 设计 Payload 数据结构
  • 决定是否需要新的追踪器枚举类型
  • 列出生命周期钩子需要执行的操作

开发阶段

  • typing.d.ts 中定义 Payload 类型
  • constant.ts 中添加追踪器类型(如需要)
  • 创建追踪器类,实现四个钩子方法
  • 编写 beforeTracking() 条件判断逻辑
  • 编写 trackingHandler() 消息发送逻辑
  • 编写 afterTracking() 清理逻辑
  • 覆盖 onTrackingError() 错误处理(如需要)

集成阶段

  • index.ts 中导出追踪器类
  • 创建对应的 React Hook(如需要)
  • useTracker.ts 中导出 Hook
  • index.ts 中导出 Hook
  • 在应用初始化时注册消息处理器
  • 实现消息处理器的具体逻辑

测试阶段

  • 测试 beforeTracking() 的条件判断
  • 测试 trackingHandler() 发送的消息内容
  • 测试 afterTracking() 的清理逻辑
  • 测试错误情况下 onTrackingError() 的处理
  • 测试消息处理器是否正确接收消息
  • 测试 React Hook 在组件挂载/卸载时的生命周期
  • 测试高频调用时的性能表现
  • 测试内存泄漏(长期运行)

文档和维护

  • 更新 README 中的使用示例
  • 添加代码注释和文档字符串
  • 编写追踪器的使用说明
  • 记录 Payload 中的各个字段含义
  • 记录消息处理器的处理逻辑

🎯 最佳实践

1. Payload 设计原则

// ✅ 好的 Payload 设计
interface MyPayload {
  // 必须字段:标识性信息
  actionId: string;
  
  // 核心字段:业务关键数据
  userId: string;
  action: string;
  
  // 可选字段:额外上下文
  metadata?: Record<string, any>;
  
  // 避免冗余:不要重复存储系统时间戳
  // 系统会自动添加到消息中的 timestamp 字段
}

2. Hook 设计原则

// ✅ 好的 Hook 设计
function useMyTracker(dependencies: any[]) {
  const trackerRef = useRef<MyTracker | null>(null);

  if (!trackerRef.current) {
    trackerRef.current = new MyTracker();
  }

  useEffect(() => {
    // Hook 只负责追踪器的创建和销毁
    // 具体的追踪逻辑由使用者决定
    return () => {
      // 可选:清理逻辑
    };
  }, dependencies);

  return trackerRef.current;
}

3. 消息处理器设计原则

// ✅ 好的消息处理器设计
messageCenter.on(TrackerType.MyType, async (message) => {
  try {
    // 1. 验证消息内容
    const payload = message.payload as Tracker.MyPayload;
    if (!payload.actionId) {
      console.warn('Invalid payload: missing actionId');
      return;
    }

    // 2. 异步处理(不阻塞)
    await sendToBackend(payload);

    // 3. 错误处理(不影响应用)
  } catch (error) {
    console.error('Failed to process message:', error);
    await reportToMonitoring(error);
  }
});

4. 避免常见陷阱

// ❌ 陷阱 1:在 beforeTracking 中进行 DOM 操作
protected async beforeTracking(payload: TPayload): Promise<boolean> {
  document.querySelector('.loading').style.display = 'none'; // ❌ 不要
  return true;
}

// ✅ 正确:只在 afterTracking 中
protected async afterTracking(payload: TPayload): Promise<void> {
  // 如果需要 DOM 操作,使用 requestAnimationFrame
  requestAnimationFrame(() => {
    document.querySelector('.loading').style.display = 'none';
  });
}

// ❌ 陷阱 2:消息处理器中未捕获异常
messageCenter.on(TrackerType.MyType, async (message) => {
  await fetch(SERVER); // ❌ 如果失败,可能导致应用崩溃
});

// ✅ 正确:总是捕获异常
messageCenter.on(TrackerType.MyType, async (message) => {
  try {
    await fetch(SERVER);
  } catch (error) {
    // 记录但不抛出
    console.error('Failed:', error);
  }
});

// ❌ 陷阱 3:同步阻塞操作
protected async trackingHandler(payload: TPayload): Promise<void> {
  const data = heavyComputationSync(payload); // ❌ 阻塞 UI
  await this.sendMessage(data);
}

// ✅ 正确:使用 Web Worker 或异步处理
protected async trackingHandler(payload: TPayload): Promise<void> {
  const data = await heavyComputationAsync(payload); // 异步处理
  await this.sendMessage(data);
}