@anker-in/analysis 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +240 -0
- package/dist/autoTrack/click.d.ts +2 -0
- package/dist/autoTrack/click.d.ts.map +1 -0
- package/dist/autoTrack/click.js +80 -0
- package/dist/autoTrack/index.d.ts +2 -0
- package/dist/autoTrack/index.d.ts.map +1 -0
- package/dist/autoTrack/index.js +47 -0
- package/dist/autoTrack/pv.d.ts +2 -0
- package/dist/autoTrack/pv.d.ts.map +1 -0
- package/dist/autoTrack/pv.js +57 -0
- package/dist/autoTrack/trackByTags.d.ts +17 -0
- package/dist/autoTrack/trackByTags.d.ts.map +1 -0
- package/dist/autoTrack/trackByTags.js +141 -0
- package/dist/constants/index.d.ts +2 -0
- package/dist/constants/index.d.ts.map +1 -0
- package/dist/constants/index.js +1 -0
- package/dist/constants/tagsMap.d.ts +9 -0
- package/dist/constants/tagsMap.d.ts.map +1 -0
- package/dist/constants/tagsMap.js +8 -0
- package/dist/core/adapters/gtag.d.ts +37 -0
- package/dist/core/adapters/gtag.d.ts.map +1 -0
- package/dist/core/adapters/gtag.js +55 -0
- package/dist/core/adapters/index.d.ts +6 -0
- package/dist/core/adapters/index.d.ts.map +1 -0
- package/dist/core/adapters/index.js +5 -0
- package/dist/core/adapters/meta.d.ts +20 -0
- package/dist/core/adapters/meta.d.ts.map +1 -0
- package/dist/core/adapters/meta.js +41 -0
- package/dist/core/helpers/function-utils.d.ts +17 -0
- package/dist/core/helpers/function-utils.d.ts.map +1 -0
- package/dist/core/helpers/function-utils.js +43 -0
- package/dist/core/helpers/index.d.ts +8 -0
- package/dist/core/helpers/index.d.ts.map +1 -0
- package/dist/core/helpers/index.js +7 -0
- package/dist/core/helpers/logger.d.ts +20 -0
- package/dist/core/helpers/logger.d.ts.map +1 -0
- package/dist/core/helpers/logger.js +32 -0
- package/dist/core/helpers/platform-detector.d.ts +14 -0
- package/dist/core/helpers/platform-detector.d.ts.map +1 -0
- package/dist/core/helpers/platform-detector.js +28 -0
- package/dist/core/helpers/script-loader.d.ts +39 -0
- package/dist/core/helpers/script-loader.d.ts.map +1 -0
- package/dist/core/helpers/script-loader.js +107 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +9 -0
- package/dist/core/track/gtagTrack.d.ts +2 -0
- package/dist/core/track/gtagTrack.d.ts.map +1 -0
- package/dist/core/track/gtagTrack.js +12 -0
- package/dist/core/track/index.d.ts +4 -0
- package/dist/core/track/index.d.ts.map +1 -0
- package/dist/core/track/index.js +3 -0
- package/dist/core/track/metaTrack.d.ts +2 -0
- package/dist/core/track/metaTrack.d.ts.map +1 -0
- package/dist/core/track/metaTrack.js +18 -0
- package/dist/core/track/track.d.ts +6 -0
- package/dist/core/track/track.d.ts.map +1 -0
- package/dist/core/track/track.js +128 -0
- package/dist/core/tracking/dispatcher.d.ts +10 -0
- package/dist/core/tracking/dispatcher.d.ts.map +1 -0
- package/dist/core/tracking/dispatcher.js +67 -0
- package/dist/core/tracking/index.d.ts +6 -0
- package/dist/core/tracking/index.d.ts.map +1 -0
- package/dist/core/tracking/index.js +5 -0
- package/dist/core/tracking/with-tracking.d.ts +33 -0
- package/dist/core/tracking/with-tracking.d.ts.map +1 -0
- package/dist/core/tracking/with-tracking.js +137 -0
- package/dist/core/utils.d.ts +64 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/core/utils.js +182 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/pixels/GtagPixel.d.ts +7 -0
- package/dist/pixels/GtagPixel.d.ts.map +1 -0
- package/dist/pixels/GtagPixel.js +73 -0
- package/dist/pixels/MetaPixel.d.ts +7 -0
- package/dist/pixels/MetaPixel.d.ts.map +1 -0
- package/dist/pixels/MetaPixel.js +61 -0
- package/dist/pixels/PixelsManager.d.ts +5 -0
- package/dist/pixels/PixelsManager.d.ts.map +1 -0
- package/dist/pixels/PixelsManager.js +17 -0
- package/dist/pixels/index.d.ts +4 -0
- package/dist/pixels/index.d.ts.map +1 -0
- package/dist/pixels/index.js +3 -0
- package/dist/types/common.d.ts +66 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +1 -0
- package/dist/types/gtag.d.ts +34 -0
- package/dist/types/gtag.d.ts.map +1 -0
- package/dist/types/gtag.js +1 -0
- package/dist/types/index.d.ts +91 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/meta.d.ts +8 -0
- package/dist/types/meta.d.ts.map +1 -0
- package/dist/types/meta.js +4 -0
- package/dist/types/trackByTags.d.ts +26 -0
- package/dist/types/trackByTags.d.ts.map +1 -0
- package/dist/types/trackByTags.js +4 -0
- package/package.json +79 -0
package/README.md
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# @anker-in/analysis
|
|
2
|
+
|
|
3
|
+
统一的埋点 SDK,支持多平台埋点接入、自动埋点、手动埋点等功能。
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- 🎯 **统一接口** - 屏蔽不同埋点平台的差异,提供统一的 API
|
|
8
|
+
- 🚀 **自动埋点** - 支持自动采集 PV、点击等通用行为
|
|
9
|
+
- 🔧 **手动埋点** - 提供简洁 API 供业务代码主动上报
|
|
10
|
+
- ⚙️ **可配置** - 支持动态开启/关闭、平台开关等
|
|
11
|
+
- 🔌 **可扩展** - 方便接入新的埋点平台
|
|
12
|
+
- 📦 **类型安全** - 完整的 TypeScript 类型定义
|
|
13
|
+
|
|
14
|
+
## 支持的平台
|
|
15
|
+
|
|
16
|
+
- ✅ Google Analytics (gtag)
|
|
17
|
+
- ✅ Meta (Facebook) Pixel
|
|
18
|
+
- 🔜 TikTok Pixel (规划中)
|
|
19
|
+
- 🔜 Scarab (规划中)
|
|
20
|
+
|
|
21
|
+
## 安装
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @anker-in/analysis
|
|
25
|
+
# 或
|
|
26
|
+
pnpm add @anker-in/analysis
|
|
27
|
+
# 或
|
|
28
|
+
yarn add @anker-in/analysis
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 快速开始
|
|
32
|
+
|
|
33
|
+
### 基础使用
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { track } from "@anker-in/analysis";
|
|
37
|
+
|
|
38
|
+
// Gtag 埋点
|
|
39
|
+
track({
|
|
40
|
+
platform: "gtag",
|
|
41
|
+
eventName: "purchase",
|
|
42
|
+
items: [
|
|
43
|
+
{
|
|
44
|
+
item_id: "SKU123",
|
|
45
|
+
item_name: "Product Name",
|
|
46
|
+
price: 99.99,
|
|
47
|
+
quantity: 1,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
value: 99.99,
|
|
51
|
+
currency: "USD",
|
|
52
|
+
transactionId: "ORDER-123",
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Meta Pixel 埋点
|
|
56
|
+
track({
|
|
57
|
+
platform: "meta",
|
|
58
|
+
event: "PageView",
|
|
59
|
+
data: {
|
|
60
|
+
page: "home",
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### TrackByTags 使用
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { trackByTags } from "@anker-in/analysis";
|
|
69
|
+
|
|
70
|
+
// 基于产品标签自动埋点
|
|
71
|
+
trackByTags({
|
|
72
|
+
tags: ["fbq:atc:1234567890", "gtag:atc:AW-123456789/abc123"],
|
|
73
|
+
data: [{ event: "atc" }],
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Pixels 组件使用
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
import { GtagPixel, MetaPixel, PixelsManager } from '@anker-in/analysis';
|
|
81
|
+
|
|
82
|
+
// 使用单个 Pixel 组件
|
|
83
|
+
<GtagPixel
|
|
84
|
+
pixelIds={['G-XXXXXXXXXX']}
|
|
85
|
+
enabled={true}
|
|
86
|
+
/>
|
|
87
|
+
|
|
88
|
+
// 使用 PixelsManager
|
|
89
|
+
<PixelsManager
|
|
90
|
+
type="gtag"
|
|
91
|
+
pixelIds={['G-XXXXXXXXXX']}
|
|
92
|
+
enabled={true}
|
|
93
|
+
/>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## API 文档
|
|
97
|
+
|
|
98
|
+
### track(config)
|
|
99
|
+
|
|
100
|
+
统一的埋点上报函数。
|
|
101
|
+
|
|
102
|
+
**参数:**
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// Gtag 埋点
|
|
106
|
+
track({
|
|
107
|
+
platform: 'gtag',
|
|
108
|
+
eventName: 'purchase' | 'add_to_cart' | 'conversion' | ...,
|
|
109
|
+
// 转化事件
|
|
110
|
+
send_to?: string,
|
|
111
|
+
value?: number,
|
|
112
|
+
currency?: string,
|
|
113
|
+
transactionId?: string,
|
|
114
|
+
// 电商事件
|
|
115
|
+
items?: GtagItem[],
|
|
116
|
+
tax?: number,
|
|
117
|
+
shipping?: number,
|
|
118
|
+
coupon?: string,
|
|
119
|
+
// 通用参数
|
|
120
|
+
measurementId?: string,
|
|
121
|
+
nonInteraction?: boolean,
|
|
122
|
+
customParams?: Record<string, any>,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Meta Pixel 埋点
|
|
126
|
+
track({
|
|
127
|
+
platform: 'meta',
|
|
128
|
+
event: string,
|
|
129
|
+
data?: Record<string, any>,
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### trackByTags(params)
|
|
134
|
+
|
|
135
|
+
基于标签的埋点功能。
|
|
136
|
+
|
|
137
|
+
**参数:**
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
trackByTags({
|
|
141
|
+
tags: string[], // 标签数组,格式: ['fbq:atc:1234567890', 'gtag:atc:AW-123456789/abc123']
|
|
142
|
+
data: TrackByTagsData[], // 事件数据数组
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Pixels 组件
|
|
147
|
+
|
|
148
|
+
#### GtagPixel
|
|
149
|
+
|
|
150
|
+
Google Analytics Pixel 组件。
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
<GtagPixel
|
|
154
|
+
pixelIds={string | string[]}
|
|
155
|
+
enabled={boolean}
|
|
156
|
+
debug?: boolean
|
|
157
|
+
/>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### MetaPixel
|
|
161
|
+
|
|
162
|
+
Meta Pixel 组件。
|
|
163
|
+
|
|
164
|
+
```tsx
|
|
165
|
+
<MetaPixel
|
|
166
|
+
pixelIds={string | string[]}
|
|
167
|
+
enabled={boolean}
|
|
168
|
+
debug?: boolean
|
|
169
|
+
/>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
#### PixelsManager
|
|
173
|
+
|
|
174
|
+
Pixel 管理器组件,根据类型自动选择对应的 Pixel 组件。
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
<PixelsManager
|
|
178
|
+
type="gtag" | "meta"
|
|
179
|
+
pixelIds={string | string[]}
|
|
180
|
+
enabled={boolean}
|
|
181
|
+
debug?: boolean
|
|
182
|
+
/>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## 类型定义
|
|
186
|
+
|
|
187
|
+
所有类型都可以从包中导入:
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
import type {
|
|
191
|
+
TrackConfig,
|
|
192
|
+
GtagTrackParams,
|
|
193
|
+
MetaTrackParams,
|
|
194
|
+
TrackByTagsData,
|
|
195
|
+
TrackByTagsParams,
|
|
196
|
+
PlatformType,
|
|
197
|
+
// ... 更多类型
|
|
198
|
+
} from "@anker-in/analysis";
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## 导出路径
|
|
202
|
+
|
|
203
|
+
包支持多个导出路径:
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
// 主入口
|
|
207
|
+
import { track } from "@anker-in/analysis";
|
|
208
|
+
|
|
209
|
+
// 类型定义
|
|
210
|
+
import type { TrackConfig } from "@anker-in/analysis/types";
|
|
211
|
+
|
|
212
|
+
// 核心功能
|
|
213
|
+
import { track } from "@anker-in/analysis/core";
|
|
214
|
+
|
|
215
|
+
// Pixels 组件
|
|
216
|
+
import { GtagPixel } from "@anker-in/analysis/pixels";
|
|
217
|
+
|
|
218
|
+
// TrackByTags
|
|
219
|
+
import { trackByTags } from "@anker-in/analysis/autoTrack";
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## 开发
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
# 安装依赖
|
|
226
|
+
pnpm install
|
|
227
|
+
|
|
228
|
+
# 构建
|
|
229
|
+
pnpm build
|
|
230
|
+
|
|
231
|
+
# 类型检查
|
|
232
|
+
pnpm check-types
|
|
233
|
+
|
|
234
|
+
# 代码检查
|
|
235
|
+
pnpm lint
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"click.d.ts","sourceRoot":"","sources":["../../src/autoTrack/click.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// import { logger, throttle } from '../core/helpers';
|
|
2
|
+
export {};
|
|
3
|
+
// /**
|
|
4
|
+
// * 获取埋点数据
|
|
5
|
+
// */
|
|
6
|
+
// function getTrackData(element: HTMLElement): Record<string, any> {
|
|
7
|
+
// const data: Record<string, any> = {};
|
|
8
|
+
// // 获取 data-track 属性
|
|
9
|
+
// const trackAttr = element.getAttribute('data-track');
|
|
10
|
+
// if (trackAttr) {
|
|
11
|
+
// try {
|
|
12
|
+
// // 尝试解析为 JSON
|
|
13
|
+
// Object.assign(data, JSON.parse(trackAttr));
|
|
14
|
+
// } catch {
|
|
15
|
+
// // 如果不是 JSON,作为普通字符串使用
|
|
16
|
+
// data.track_id = trackAttr;
|
|
17
|
+
// }
|
|
18
|
+
// }
|
|
19
|
+
// // 获取其他 data-track-* 属性
|
|
20
|
+
// Array.from(element.attributes).forEach(attr => {
|
|
21
|
+
// if (attr.name.startsWith('data-track-')) {
|
|
22
|
+
// const key = attr.name.replace('data-track-', '');
|
|
23
|
+
// data[key] = attr.value;
|
|
24
|
+
// }
|
|
25
|
+
// });
|
|
26
|
+
// // 补充基础信息
|
|
27
|
+
// data.element_tag = element.tagName.toLowerCase();
|
|
28
|
+
// data.element_text = element.textContent?.trim().substring(0, 100);
|
|
29
|
+
// data.element_id = element.id;
|
|
30
|
+
// data.element_class = element.className;
|
|
31
|
+
// return data;
|
|
32
|
+
// }
|
|
33
|
+
// /**
|
|
34
|
+
// * 点击自动埋点
|
|
35
|
+
// */
|
|
36
|
+
// export function createClickAutoTrack(trackFn: (type: string, params: any) => void) {
|
|
37
|
+
// let enabled = false;
|
|
38
|
+
// let selector = '[data-track]';
|
|
39
|
+
// let clickHandler: ((e: Event) => void) | null = null;
|
|
40
|
+
// const handleClick = (e: Event) => {
|
|
41
|
+
// if (!enabled) return;
|
|
42
|
+
// const target = e.target as HTMLElement;
|
|
43
|
+
// if (!target) return;
|
|
44
|
+
// // 查找最近的匹配元素
|
|
45
|
+
// const element = target.closest(selector);
|
|
46
|
+
// if (!element) return;
|
|
47
|
+
// // 获取埋点数据
|
|
48
|
+
// const trackData = getTrackData(element as HTMLElement);
|
|
49
|
+
// trackFn('click', {
|
|
50
|
+
// ...trackData,
|
|
51
|
+
// timestamp: Date.now(),
|
|
52
|
+
// });
|
|
53
|
+
// logger.log('Click tracked:', trackData);
|
|
54
|
+
// };
|
|
55
|
+
// return {
|
|
56
|
+
// enable(customSelector?: string) {
|
|
57
|
+
// if (enabled) {
|
|
58
|
+
// logger.warn('Click auto track already enabled');
|
|
59
|
+
// return;
|
|
60
|
+
// }
|
|
61
|
+
// if (customSelector) {
|
|
62
|
+
// selector = customSelector;
|
|
63
|
+
// }
|
|
64
|
+
// enabled = true;
|
|
65
|
+
// // 使用事件委托监听点击
|
|
66
|
+
// clickHandler = throttle(handleClick, 300);
|
|
67
|
+
// document.addEventListener('click', clickHandler, true);
|
|
68
|
+
// logger.log(`Click auto track enabled with selector: ${selector}`);
|
|
69
|
+
// },
|
|
70
|
+
// disable() {
|
|
71
|
+
// if (!enabled) return;
|
|
72
|
+
// enabled = false;
|
|
73
|
+
// if (clickHandler) {
|
|
74
|
+
// document.removeEventListener('click', clickHandler, true);
|
|
75
|
+
// clickHandler = null;
|
|
76
|
+
// }
|
|
77
|
+
// logger.log('Click auto track disabled');
|
|
78
|
+
// },
|
|
79
|
+
// };
|
|
80
|
+
// }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/autoTrack/index.ts"],"names":[],"mappings":"AAuDA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// import type { AutoTrackConfig } from "../types";
|
|
2
|
+
// import { createPVAutoTrack } from "./pv";
|
|
3
|
+
// import { createClickAutoTrack } from "./click";
|
|
4
|
+
// import { logger } from "../core/helpers";
|
|
5
|
+
// /**
|
|
6
|
+
// * 创建自动埋点管理器
|
|
7
|
+
// */
|
|
8
|
+
// export function createAutoTrackManager(
|
|
9
|
+
// trackFn: (type: string, params: any) => void
|
|
10
|
+
// ) {
|
|
11
|
+
// const pvTracker = createPVAutoTrack(trackFn);
|
|
12
|
+
// const clickTracker = createClickAutoTrack(trackFn);
|
|
13
|
+
// let config: AutoTrackConfig = {};
|
|
14
|
+
// return {
|
|
15
|
+
// init(autoTrackConfig: AutoTrackConfig = {}) {
|
|
16
|
+
// config = autoTrackConfig;
|
|
17
|
+
// // PV 自动埋点(默认开启)
|
|
18
|
+
// if (autoTrackConfig.pv !== false) {
|
|
19
|
+
// pvTracker.enable();
|
|
20
|
+
// }
|
|
21
|
+
// // 点击自动埋点
|
|
22
|
+
// if (autoTrackConfig.click) {
|
|
23
|
+
// clickTracker.enable(autoTrackConfig.clickSelector);
|
|
24
|
+
// }
|
|
25
|
+
// logger.log("AutoTrack initialized with config:", autoTrackConfig);
|
|
26
|
+
// },
|
|
27
|
+
// disable() {
|
|
28
|
+
// pvTracker.disable();
|
|
29
|
+
// clickTracker.disable();
|
|
30
|
+
// logger.log("All auto tracks disabled");
|
|
31
|
+
// },
|
|
32
|
+
// getConfig() {
|
|
33
|
+
// return config;
|
|
34
|
+
// },
|
|
35
|
+
// // 导出单独的 tracker 以便直接控制
|
|
36
|
+
// pv: pvTracker,
|
|
37
|
+
// click: clickTracker,
|
|
38
|
+
// };
|
|
39
|
+
// }
|
|
40
|
+
// export { createPVAutoTrack, createClickAutoTrack };
|
|
41
|
+
// export {
|
|
42
|
+
// trackByTags,
|
|
43
|
+
// createTrackByTagsManager,
|
|
44
|
+
// type TrackByTagsData,
|
|
45
|
+
// TrackTagsVersionMap,
|
|
46
|
+
// } from "./trackByTags";
|
|
47
|
+
export { trackByTags } from "./trackByTags";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pv.d.ts","sourceRoot":"","sources":["../../src/autoTrack/pv.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// import { logger } from '../core/helpers';
|
|
2
|
+
export {};
|
|
3
|
+
// /**
|
|
4
|
+
// * PV 自动埋点
|
|
5
|
+
// */
|
|
6
|
+
// export function createPVAutoTrack(trackFn: (type: string, params: any) => void) {
|
|
7
|
+
// let enabled = false;
|
|
8
|
+
// let tracked = false;
|
|
9
|
+
// const trackPageView = () => {
|
|
10
|
+
// if (!enabled) return;
|
|
11
|
+
// trackFn('pv', {
|
|
12
|
+
// page_url: window.location.href,
|
|
13
|
+
// page_title: document.title,
|
|
14
|
+
// referrer: document.referrer,
|
|
15
|
+
// timestamp: Date.now(),
|
|
16
|
+
// });
|
|
17
|
+
// tracked = true;
|
|
18
|
+
// };
|
|
19
|
+
// const setupRouteListener = () => {
|
|
20
|
+
// // 监听 history API
|
|
21
|
+
// const originalPushState = history.pushState;
|
|
22
|
+
// const originalReplaceState = history.replaceState;
|
|
23
|
+
// history.pushState = function (...args) {
|
|
24
|
+
// originalPushState.apply(this, args);
|
|
25
|
+
// trackPageView();
|
|
26
|
+
// };
|
|
27
|
+
// history.replaceState = function (...args) {
|
|
28
|
+
// originalReplaceState.apply(this, args);
|
|
29
|
+
// trackPageView();
|
|
30
|
+
// };
|
|
31
|
+
// // 监听 popstate 事件
|
|
32
|
+
// window.addEventListener('popstate', trackPageView);
|
|
33
|
+
// // 监听 hashchange 事件
|
|
34
|
+
// window.addEventListener('hashchange', trackPageView);
|
|
35
|
+
// };
|
|
36
|
+
// return {
|
|
37
|
+
// enable() {
|
|
38
|
+
// if (enabled) {
|
|
39
|
+
// logger.warn('PV auto track already enabled');
|
|
40
|
+
// return;
|
|
41
|
+
// }
|
|
42
|
+
// enabled = true;
|
|
43
|
+
// // 立即上报一次 PV
|
|
44
|
+
// trackPageView();
|
|
45
|
+
// // 监听路由变化(适配 SPA)
|
|
46
|
+
// setupRouteListener();
|
|
47
|
+
// logger.log('PV auto track enabled');
|
|
48
|
+
// },
|
|
49
|
+
// disable() {
|
|
50
|
+
// enabled = false;
|
|
51
|
+
// logger.log('PV auto track disabled');
|
|
52
|
+
// },
|
|
53
|
+
// isTracked() {
|
|
54
|
+
// return tracked;
|
|
55
|
+
// },
|
|
56
|
+
// };
|
|
57
|
+
// }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TrackByTagsParams } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* 基于标签进行埋点上报
|
|
4
|
+
*
|
|
5
|
+
* @param tags - 标签数组,格式: ['fbq:atc:1234567890', 'gtag:atc:AW-123456789/abc123']
|
|
6
|
+
* @param data - 事件数据数组,每个元素包含 event 字段用于匹配标签
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* trackByTags(
|
|
11
|
+
* ['fbq:atc:1234567890', 'gtag:atc:AW-123456789/abc123'],
|
|
12
|
+
* [{ event: 'atc' }]
|
|
13
|
+
* );
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function trackByTags({ tags, data }: TrackByTagsParams): void;
|
|
17
|
+
//# sourceMappingURL=trackByTags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trackByTags.d.ts","sourceRoot":"","sources":["../../src/autoTrack/trackByTags.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA0B,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAmG1E;;;;;;;;;;;;;GAaG;AAEH,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,iBAAiB,GAAG,IAAI,CAgDnE"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { track } from "../core/tracking";
|
|
2
|
+
import { logger } from "../core/helpers";
|
|
3
|
+
import { TrackTagsVersionMap } from "../constants";
|
|
4
|
+
/**
|
|
5
|
+
* 解析单个标签
|
|
6
|
+
*/
|
|
7
|
+
function parseTag(tag) {
|
|
8
|
+
const parts = tag.split(":");
|
|
9
|
+
if (parts.length < 2) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
media: parts[0]?.toLowerCase() || "",
|
|
14
|
+
event: parts[1]?.toLowerCase() || "",
|
|
15
|
+
target: parts[2] || null,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 适配事件名称(版本兼容)
|
|
20
|
+
* 将旧版本的事件名替换为新版本的事件名
|
|
21
|
+
*/
|
|
22
|
+
function adaptEventName(tags) {
|
|
23
|
+
for (let i = 0; i < tags.length; i++) {
|
|
24
|
+
if (!tags[i]) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
for (const [oldEvent, newEvent] of Object.entries(TrackTagsVersionMap)) {
|
|
28
|
+
if (tags[i]?.includes(oldEvent)) {
|
|
29
|
+
tags[i] = tags[i]?.replace(oldEvent, newEvent) ?? "";
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 根据事件标识符过滤标签
|
|
37
|
+
*/
|
|
38
|
+
function filterTagsByEvent(tags, eventSymbol) {
|
|
39
|
+
return tags.filter((tag) => {
|
|
40
|
+
const parsed = parseTag(tag);
|
|
41
|
+
return parsed?.event === eventSymbol.toLowerCase();
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 处理单个标签的埋点
|
|
46
|
+
*/
|
|
47
|
+
function handleTagTracking(parsedTag,
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
49
|
+
eventData) {
|
|
50
|
+
const { media, event, target } = parsedTag;
|
|
51
|
+
if (!target) {
|
|
52
|
+
logger.warn(`Tag missing target: ${media}:${event}`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
switch (media) {
|
|
57
|
+
case "fbq":
|
|
58
|
+
case "meta": {
|
|
59
|
+
// Meta Pixel 埋点
|
|
60
|
+
const config = {
|
|
61
|
+
platform: "meta",
|
|
62
|
+
event: target, // target 作为事件名
|
|
63
|
+
data: eventData,
|
|
64
|
+
};
|
|
65
|
+
track(config);
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
case "gtag": {
|
|
69
|
+
// Gtag 转化事件埋点
|
|
70
|
+
const config = {
|
|
71
|
+
platform: "gtag",
|
|
72
|
+
eventName: "conversion",
|
|
73
|
+
send_to: target, // target 作为转化目标ID
|
|
74
|
+
value: eventData?.value ?? 1.0,
|
|
75
|
+
currency: eventData?.currency,
|
|
76
|
+
transactionId: eventData?.transactionId,
|
|
77
|
+
};
|
|
78
|
+
track(config);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
default:
|
|
82
|
+
logger.warn(`Unsupported media platform: ${media}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
logger.error(`Failed to track tag ${media}:${event}:${target}:`, error);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 基于标签进行埋点上报
|
|
91
|
+
*
|
|
92
|
+
* @param tags - 标签数组,格式: ['fbq:atc:1234567890', 'gtag:atc:AW-123456789/abc123']
|
|
93
|
+
* @param data - 事件数据数组,每个元素包含 event 字段用于匹配标签
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* trackByTags(
|
|
98
|
+
* ['fbq:atc:1234567890', 'gtag:atc:AW-123456789/abc123'],
|
|
99
|
+
* [{ event: 'atc' }]
|
|
100
|
+
* );
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export function trackByTags({ tags, data }) {
|
|
104
|
+
if (!tags || tags.length === 0) {
|
|
105
|
+
logger.warn("trackByTags: tags array is empty");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (!data || data.length === 0) {
|
|
109
|
+
logger.warn("trackByTags: data array is empty");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
// 数据清洗:兼容旧版本标签
|
|
113
|
+
const adaptedTags = [...tags];
|
|
114
|
+
adaptEventName(adaptedTags);
|
|
115
|
+
// 处理每个事件数据
|
|
116
|
+
data.forEach((trackData) => {
|
|
117
|
+
const eventSymbol = trackData.event?.toLowerCase();
|
|
118
|
+
if (!eventSymbol) {
|
|
119
|
+
logger.warn("trackByTags: event symbol is missing in trackData");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// 根据事件标识符过滤标签
|
|
123
|
+
const matchedTags = filterTagsByEvent(adaptedTags, eventSymbol);
|
|
124
|
+
if (matchedTags.length === 0) {
|
|
125
|
+
logger.log(`trackByTags: No tags found for event: ${eventSymbol}`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
// 提取事件数据(排除 event 字段)
|
|
129
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
130
|
+
const { event, ...eventData } = trackData;
|
|
131
|
+
// 处理每个匹配的标签
|
|
132
|
+
matchedTags.forEach((tag) => {
|
|
133
|
+
const parsed = parseTag(tag);
|
|
134
|
+
if (!parsed) {
|
|
135
|
+
logger.warn(`trackByTags: Invalid tag format: ${tag}`);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
handleTagTracking(parsed, eventData);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TrackTagsVersionMap } from "./tagsMap";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tagsMap.d.ts","sourceRoot":"","sources":["../../src/constants/tagsMap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,mBAAmB;;;CAGtB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Analytics / gtag.js 适配器
|
|
3
|
+
* 使用标准的 window.gtag() API
|
|
4
|
+
* 专注于转化事件追踪
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* gtag 命令类型
|
|
8
|
+
*/
|
|
9
|
+
type GtagCommand = "config" | "event" | "set" | "get";
|
|
10
|
+
/**
|
|
11
|
+
* gtag 埋点函数
|
|
12
|
+
* 调用 window.gtag() 标准 API
|
|
13
|
+
*/
|
|
14
|
+
export declare const gtagTrack: (command: GtagCommand, targetOrEventName: string, params?: Record<string, any>) => void;
|
|
15
|
+
/**
|
|
16
|
+
* 发送 gtag 事件
|
|
17
|
+
*/
|
|
18
|
+
export declare const gtagEvent: (eventName: string, eventParams?: Record<string, any>) => void;
|
|
19
|
+
/**
|
|
20
|
+
* 发送 gtag config
|
|
21
|
+
*/
|
|
22
|
+
export declare const gtagConfig: (measurementId: string, configParams?: Record<string, any>) => void;
|
|
23
|
+
/**
|
|
24
|
+
* 检测 gtag 是否可用
|
|
25
|
+
*/
|
|
26
|
+
export declare const isGtagAvailable: () => boolean;
|
|
27
|
+
/**
|
|
28
|
+
* gtag 适配器对象
|
|
29
|
+
*/
|
|
30
|
+
export declare const gtagAdapter: {
|
|
31
|
+
track: (command: GtagCommand, targetOrEventName: string, params?: Record<string, any>) => void;
|
|
32
|
+
event: (eventName: string, eventParams?: Record<string, any>) => void;
|
|
33
|
+
config: (measurementId: string, configParams?: Record<string, any>) => void;
|
|
34
|
+
isAvailable: () => boolean;
|
|
35
|
+
};
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=gtag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gtag.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/gtag.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,KAAK,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,GAAG,KAAK,CAAC;AAEtD;;;GAGG;AACH,eAAO,MAAM,SAAS,GACpB,SAAS,WAAW,EACpB,mBAAmB,MAAM,EACzB,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC3B,IAgBF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,GACpB,WAAW,MAAM,EACjB,cAAc,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAChC,IAEF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,GACrB,eAAe,MAAM,EACrB,eAAe,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KACjC,IAEF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,QAAO,OAKlC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW;qBAtDb,WAAW,qBACD,MAAM,WAChB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC3B,IAAI;uBAsBM,MAAM,gBACH,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAChC,IAAI;4BAQU,MAAM,iBACN,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KACjC,IAAI;uBAO4B,OAAO;CAezC,CAAC"}
|