@gctrack/behavior 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 yinuo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # @gctrack/behavior
2
+
3
+ 行为监控 —— 页面浏览(PV)、点击、滚动深度、页面停留、可见性、用户活跃度,以及表单交互、搜索、视频等业务行为采集。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm i @gctrack/behavior @gctrack/core
9
+ ```
10
+
11
+ ## 用法
12
+
13
+ ```ts
14
+ import { createTracker } from '@gctrack/core'
15
+ import { createBehaviorMonitor } from '@gctrack/behavior'
16
+
17
+ const tracker = createTracker({ reportUrl: '...', appKey: '...' })
18
+ const behavior = createBehaviorMonitor(tracker)
19
+ behavior.start()
20
+
21
+ // 业务侧手动调用
22
+ behavior.trackSearch('酒店', 42)
23
+ behavior.trackVideo('v1', 'play')
24
+ const form = behavior.trackFormInteraction('login')
25
+ form.onSubmit(true)
26
+ ```
27
+
28
+ ## License
29
+
30
+ MIT (c) yinuo
package/dist/index.cjs ADDED
@@ -0,0 +1,244 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _gctrack_core = require("@gctrack/core");
3
+ //#region src/index.ts
4
+ /**
5
+ * 行为监控插件
6
+ */
7
+ var BehaviorMonitor = class {
8
+ constructor(tracker) {
9
+ this.sessionStartTime = Date.now();
10
+ this.pageStartTime = Date.now();
11
+ this.clickCount = 0;
12
+ this.scrollDepth = 0;
13
+ this.tracker = tracker;
14
+ }
15
+ /**
16
+ * 启动行为监控
17
+ */
18
+ start() {
19
+ if (typeof window === "undefined") return;
20
+ this.trackPageView();
21
+ this.trackPageStay();
22
+ this.trackClick();
23
+ this.trackScroll();
24
+ this.trackVisibility();
25
+ this.trackUserEngagement();
26
+ }
27
+ /**
28
+ * 追踪页面浏览
29
+ */
30
+ trackPageView() {
31
+ this.tracker.track("page_view", {
32
+ screenWidth: window.screen.width,
33
+ screenHeight: window.screen.height,
34
+ viewportWidth: window.innerWidth,
35
+ viewportHeight: window.innerHeight,
36
+ timestamp: Date.now()
37
+ });
38
+ }
39
+ /**
40
+ * 追踪页面停留时间
41
+ */
42
+ trackPageStay() {
43
+ const reportStayTime = () => {
44
+ const stayTime = Date.now() - this.pageStartTime;
45
+ this.tracker.track("page_stay", {
46
+ stayTime,
47
+ clickCount: this.clickCount,
48
+ maxScrollDepth: this.scrollDepth,
49
+ timestamp: Date.now()
50
+ });
51
+ };
52
+ window.addEventListener("beforeunload", reportStayTime);
53
+ document.addEventListener("visibilitychange", () => {
54
+ if (document.visibilityState === "hidden") reportStayTime();
55
+ else if (document.visibilityState === "visible") {
56
+ this.pageStartTime = Date.now();
57
+ this.clickCount = 0;
58
+ }
59
+ });
60
+ }
61
+ /**
62
+ * 追踪点击行为
63
+ */
64
+ trackClick() {
65
+ document.addEventListener("click", (event) => {
66
+ this.clickCount++;
67
+ const target = event.target;
68
+ const tagName = target.tagName.toLowerCase();
69
+ const elementId = target.id || "";
70
+ const elementClass = target.className || "";
71
+ const elementText = this.getElementText(target);
72
+ const elementPath = this.getElementPath(target);
73
+ if (this.isImportantElement(target)) this.tracker.track("click", {
74
+ tagName,
75
+ elementId,
76
+ elementClass,
77
+ elementText,
78
+ elementPath,
79
+ x: event.clientX,
80
+ y: event.clientY,
81
+ timestamp: Date.now()
82
+ });
83
+ }, true);
84
+ }
85
+ /**
86
+ * 获取元素文本内容
87
+ */
88
+ getElementText(element) {
89
+ return (element.innerText || element.textContent || "").trim().substring(0, 50);
90
+ }
91
+ /**
92
+ * 获取元素路径
93
+ */
94
+ getElementPath(element) {
95
+ const path = [];
96
+ let current = element;
97
+ while (current && current !== document.body) {
98
+ let selector = current.tagName.toLowerCase();
99
+ if (current.id) {
100
+ selector += `#${current.id}`;
101
+ path.unshift(selector);
102
+ break;
103
+ } else if (current.className) {
104
+ const classes = current.className.split(" ").filter((c) => c).join(".");
105
+ if (classes) selector += `.${classes}`;
106
+ }
107
+ path.unshift(selector);
108
+ current = current.parentElement;
109
+ if (path.length >= 5) break;
110
+ }
111
+ return path.join(" > ");
112
+ }
113
+ /**
114
+ * 判断是否为重要元素
115
+ */
116
+ isImportantElement(element) {
117
+ const tagName = element.tagName.toLowerCase();
118
+ if ([
119
+ "a",
120
+ "button",
121
+ "input",
122
+ "select",
123
+ "textarea"
124
+ ].includes(tagName)) return true;
125
+ if (element.onclick || element.getAttribute("onclick")) return true;
126
+ if (element.hasAttribute("data-track") || element.classList.contains("track-click")) return true;
127
+ return false;
128
+ }
129
+ /**
130
+ * 追踪滚动深度
131
+ */
132
+ trackScroll() {
133
+ const handleScroll = (0, _gctrack_core.throttle)(() => {
134
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
135
+ const scrollHeight = document.documentElement.scrollHeight;
136
+ const clientHeight = window.innerHeight;
137
+ const scrollPercent = Math.round(scrollTop / (scrollHeight - clientHeight) * 100);
138
+ if (scrollPercent > this.scrollDepth) {
139
+ this.scrollDepth = scrollPercent;
140
+ if (scrollPercent >= 25 && scrollPercent % 25 === 0) this.tracker.track("scroll_depth", {
141
+ depth: scrollPercent,
142
+ timestamp: Date.now()
143
+ });
144
+ }
145
+ }, 300);
146
+ window.addEventListener("scroll", handleScroll);
147
+ }
148
+ /**
149
+ * 追踪页面可见性
150
+ */
151
+ trackVisibility() {
152
+ document.addEventListener("visibilitychange", () => {
153
+ this.tracker.track("visibility_change", {
154
+ state: document.visibilityState,
155
+ timestamp: Date.now()
156
+ });
157
+ });
158
+ }
159
+ /**
160
+ * 追踪用户参与度
161
+ */
162
+ trackUserEngagement() {
163
+ let inactiveTimer = null;
164
+ const resetInactiveTimer = () => {
165
+ if (inactiveTimer) clearTimeout(inactiveTimer);
166
+ inactiveTimer = setTimeout(() => {
167
+ this.tracker.track("user_inactive", {
168
+ inactiveDuration: 6e4,
169
+ timestamp: Date.now()
170
+ });
171
+ }, 6e4);
172
+ };
173
+ [
174
+ "mousedown",
175
+ "mousemove",
176
+ "keypress",
177
+ "scroll",
178
+ "touchstart"
179
+ ].forEach((event) => {
180
+ document.addEventListener(event, resetInactiveTimer, true);
181
+ });
182
+ resetInactiveTimer();
183
+ }
184
+ /**
185
+ * 追踪表单交互
186
+ */
187
+ trackFormInteraction(formName) {
188
+ return {
189
+ onFocus: () => {
190
+ this.tracker.track("form_start", {
191
+ formName,
192
+ timestamp: Date.now()
193
+ });
194
+ },
195
+ onSubmit: (success, data = {}) => {
196
+ this.tracker.track("form_submit", {
197
+ formName,
198
+ success,
199
+ ...data,
200
+ timestamp: Date.now()
201
+ });
202
+ },
203
+ onAbandon: (fieldName) => {
204
+ this.tracker.track("form_abandon", {
205
+ formName,
206
+ fieldName,
207
+ timestamp: Date.now()
208
+ });
209
+ }
210
+ };
211
+ }
212
+ /**
213
+ * 追踪搜索行为
214
+ */
215
+ trackSearch(keyword, resultCount) {
216
+ this.tracker.track("search", {
217
+ keyword,
218
+ resultCount,
219
+ timestamp: Date.now()
220
+ });
221
+ }
222
+ /**
223
+ * 追踪视频播放
224
+ */
225
+ trackVideo(videoId, action, data = {}) {
226
+ this.tracker.track("video_action", {
227
+ videoId,
228
+ action,
229
+ ...data,
230
+ timestamp: Date.now()
231
+ });
232
+ }
233
+ };
234
+ /**
235
+ * 创建行为监控实例
236
+ */
237
+ function createBehaviorMonitor(tracker) {
238
+ return new BehaviorMonitor(tracker);
239
+ }
240
+ //#endregion
241
+ exports.BehaviorMonitor = BehaviorMonitor;
242
+ exports.createBehaviorMonitor = createBehaviorMonitor;
243
+
244
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Tracker } from '@gctrack/core'\nimport { throttle } from '@gctrack/core'\n\n/**\n * 行为监控插件\n */\nexport class BehaviorMonitor {\n private tracker: Tracker\n private sessionStartTime = Date.now()\n private pageStartTime = Date.now()\n private clickCount = 0\n private scrollDepth = 0\n\n constructor(tracker: Tracker) {\n this.tracker = tracker\n }\n\n /**\n * 启动行为监控\n */\n start(): void {\n if (typeof window === 'undefined') {\n return\n }\n\n this.trackPageView()\n this.trackPageStay()\n this.trackClick()\n this.trackScroll()\n this.trackVisibility()\n this.trackUserEngagement()\n }\n\n /**\n * 追踪页面浏览\n */\n private trackPageView(): void {\n this.tracker.track('page_view', {\n screenWidth: window.screen.width,\n screenHeight: window.screen.height,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n timestamp: Date.now(),\n })\n }\n\n /**\n * 追踪页面停留时间\n */\n private trackPageStay(): void {\n // 页面卸载时上报停留时间\n const reportStayTime = () => {\n const stayTime = Date.now() - this.pageStartTime\n\n this.tracker.track('page_stay', {\n stayTime,\n clickCount: this.clickCount,\n maxScrollDepth: this.scrollDepth,\n timestamp: Date.now(),\n })\n }\n\n window.addEventListener('beforeunload', reportStayTime)\n\n // 页面隐藏时也上报(移动端)\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n reportStayTime()\n }\n else if (document.visibilityState === 'visible') {\n // 页面重新可见时重置计时\n this.pageStartTime = Date.now()\n this.clickCount = 0\n }\n })\n }\n\n /**\n * 追踪点击行为\n */\n private trackClick(): void {\n document.addEventListener(\n 'click',\n (event) => {\n this.clickCount++\n\n const target = event.target as HTMLElement\n const tagName = target.tagName.toLowerCase()\n\n // 获取元素的唯一标识\n const elementId = target.id || ''\n const elementClass = target.className || ''\n const elementText = this.getElementText(target)\n const elementPath = this.getElementPath(target)\n\n // 只上报重要元素的点击\n if (this.isImportantElement(target)) {\n this.tracker.track('click', {\n tagName,\n elementId,\n elementClass,\n elementText,\n elementPath,\n x: event.clientX,\n y: event.clientY,\n timestamp: Date.now(),\n })\n }\n },\n true,\n )\n }\n\n /**\n * 获取元素文本内容\n */\n private getElementText(element: HTMLElement): string {\n const text = element.innerText || element.textContent || ''\n return text.trim().substring(0, 50) // 限制长度\n }\n\n /**\n * 获取元素路径\n */\n private getElementPath(element: HTMLElement): string {\n const path: string[] = []\n let current: HTMLElement | null = element\n\n while (current && current !== document.body) {\n let selector = current.tagName.toLowerCase()\n\n if (current.id) {\n selector += `#${current.id}`\n path.unshift(selector)\n break // ID 是唯一的,可以停止\n }\n else if (current.className) {\n const classes = current.className.split(' ').filter(c => c).join('.')\n if (classes) {\n selector += `.${classes}`\n }\n }\n\n path.unshift(selector)\n current = current.parentElement\n\n // 限制路径深度\n if (path.length >= 5)\n break\n }\n\n return path.join(' > ')\n }\n\n /**\n * 判断是否为重要元素\n */\n private isImportantElement(element: HTMLElement): boolean {\n const tagName = element.tagName.toLowerCase()\n const importantTags = ['a', 'button', 'input', 'select', 'textarea']\n\n // 标签类型判断\n if (importantTags.includes(tagName)) {\n return true\n }\n\n // 带有点击事件的元素\n if ((element as any).onclick || element.getAttribute('onclick')) {\n return true\n }\n\n // 带有特定 class 或 data 属性的元素\n if (\n element.hasAttribute('data-track')\n || element.classList.contains('track-click')\n ) {\n return true\n }\n\n return false\n }\n\n /**\n * 追踪滚动深度\n */\n private trackScroll(): void {\n const handleScroll = throttle(() => {\n const scrollTop = window.pageYOffset || document.documentElement.scrollTop\n const scrollHeight = document.documentElement.scrollHeight\n const clientHeight = window.innerHeight\n\n const scrollPercent = Math.round((scrollTop / (scrollHeight - clientHeight)) * 100)\n\n // 更新最大滚动深度\n if (scrollPercent > this.scrollDepth) {\n this.scrollDepth = scrollPercent\n\n // 每 25% 上报一次\n if (scrollPercent >= 25 && scrollPercent % 25 === 0) {\n this.tracker.track('scroll_depth', {\n depth: scrollPercent,\n timestamp: Date.now(),\n })\n }\n }\n }, 300)\n\n window.addEventListener('scroll', handleScroll)\n }\n\n /**\n * 追踪页面可见性\n */\n private trackVisibility(): void {\n document.addEventListener('visibilitychange', () => {\n this.tracker.track('visibility_change', {\n state: document.visibilityState,\n timestamp: Date.now(),\n })\n })\n }\n\n /**\n * 追踪用户参与度\n */\n private trackUserEngagement(): void {\n let inactiveTimer: ReturnType<typeof setTimeout> | null = null\n\n const resetInactiveTimer = () => {\n if (inactiveTimer) {\n clearTimeout(inactiveTimer)\n }\n\n inactiveTimer = setTimeout(() => {\n this.tracker.track('user_inactive', {\n inactiveDuration: 60000, // 1 分钟\n timestamp: Date.now(),\n })\n }, 60000)\n }\n\n // 监听用户活动\n const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart']\n events.forEach((event) => {\n document.addEventListener(event, resetInactiveTimer, true)\n })\n\n resetInactiveTimer()\n }\n\n /**\n * 追踪表单交互\n */\n trackFormInteraction(formName: string): {\n onFocus: () => void\n onSubmit: (success: boolean, data?: Record<string, any>) => void\n onAbandon: (fieldName: string) => void\n } {\n return {\n // 表单开始填写\n onFocus: () => {\n this.tracker.track('form_start', {\n formName,\n timestamp: Date.now(),\n })\n },\n\n // 表单提交\n onSubmit: (success: boolean, data: Record<string, any> = {}) => {\n this.tracker.track('form_submit', {\n formName,\n success,\n ...data,\n timestamp: Date.now(),\n })\n },\n\n // 表单放弃\n onAbandon: (fieldName: string) => {\n this.tracker.track('form_abandon', {\n formName,\n fieldName,\n timestamp: Date.now(),\n })\n },\n }\n }\n\n /**\n * 追踪搜索行为\n */\n trackSearch(keyword: string, resultCount: number): void {\n this.tracker.track('search', {\n keyword,\n resultCount,\n timestamp: Date.now(),\n })\n }\n\n /**\n * 追踪视频播放\n */\n trackVideo(videoId: string, action: string, data: Record<string, any> = {}): void {\n this.tracker.track('video_action', {\n videoId,\n action, // play, pause, ended, error\n ...data,\n timestamp: Date.now(),\n })\n }\n}\n\n/**\n * 创建行为监控实例\n */\nexport function createBehaviorMonitor(tracker: Tracker): BehaviorMonitor {\n return new BehaviorMonitor(tracker)\n}\n"],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { Tracker } from "@gctrack/core";
2
+ export declare class BehaviorMonitor {
3
+ private tracker;
4
+ private sessionStartTime;
5
+ private pageStartTime;
6
+ private clickCount;
7
+ private scrollDepth;
8
+ constructor(tracker: Tracker);
9
+ start(): void;
10
+ private trackPageView;
11
+ private trackPageStay;
12
+ private trackClick;
13
+ private getElementText;
14
+ private getElementPath;
15
+ private isImportantElement;
16
+ private trackScroll;
17
+ private trackVisibility;
18
+ private trackUserEngagement;
19
+ trackFormInteraction(formName: string): {
20
+ onFocus: () => void;
21
+ onSubmit: (success: boolean, data?: Record<string, any>) => void;
22
+ onAbandon: (fieldName: string) => void;
23
+ };
24
+ trackSearch(keyword: string, resultCount: number): void;
25
+ trackVideo(videoId: string, action: string, data?: Record<string, any>): void;
26
+ }
27
+ export declare function createBehaviorMonitor(tracker: Tracker): BehaviorMonitor;
@@ -0,0 +1,27 @@
1
+ import type { Tracker } from "@gctrack/core";
2
+ export declare class BehaviorMonitor {
3
+ private tracker;
4
+ private sessionStartTime;
5
+ private pageStartTime;
6
+ private clickCount;
7
+ private scrollDepth;
8
+ constructor(tracker: Tracker);
9
+ start(): void;
10
+ private trackPageView;
11
+ private trackPageStay;
12
+ private trackClick;
13
+ private getElementText;
14
+ private getElementPath;
15
+ private isImportantElement;
16
+ private trackScroll;
17
+ private trackVisibility;
18
+ private trackUserEngagement;
19
+ trackFormInteraction(formName: string): {
20
+ onFocus: () => void;
21
+ onSubmit: (success: boolean, data?: Record<string, any>) => void;
22
+ onAbandon: (fieldName: string) => void;
23
+ };
24
+ trackSearch(keyword: string, resultCount: number): void;
25
+ trackVideo(videoId: string, action: string, data?: Record<string, any>): void;
26
+ }
27
+ export declare function createBehaviorMonitor(tracker: Tracker): BehaviorMonitor;
package/dist/index.js ADDED
@@ -0,0 +1,243 @@
1
+ import "node:module";
2
+ import { throttle } from "@gctrack/core";
3
+ //#region src/index.ts
4
+ /**
5
+ * 行为监控插件
6
+ */
7
+ var BehaviorMonitor = class {
8
+ constructor(tracker) {
9
+ this.sessionStartTime = Date.now();
10
+ this.pageStartTime = Date.now();
11
+ this.clickCount = 0;
12
+ this.scrollDepth = 0;
13
+ this.tracker = tracker;
14
+ }
15
+ /**
16
+ * 启动行为监控
17
+ */
18
+ start() {
19
+ if (typeof window === "undefined") return;
20
+ this.trackPageView();
21
+ this.trackPageStay();
22
+ this.trackClick();
23
+ this.trackScroll();
24
+ this.trackVisibility();
25
+ this.trackUserEngagement();
26
+ }
27
+ /**
28
+ * 追踪页面浏览
29
+ */
30
+ trackPageView() {
31
+ this.tracker.track("page_view", {
32
+ screenWidth: window.screen.width,
33
+ screenHeight: window.screen.height,
34
+ viewportWidth: window.innerWidth,
35
+ viewportHeight: window.innerHeight,
36
+ timestamp: Date.now()
37
+ });
38
+ }
39
+ /**
40
+ * 追踪页面停留时间
41
+ */
42
+ trackPageStay() {
43
+ const reportStayTime = () => {
44
+ const stayTime = Date.now() - this.pageStartTime;
45
+ this.tracker.track("page_stay", {
46
+ stayTime,
47
+ clickCount: this.clickCount,
48
+ maxScrollDepth: this.scrollDepth,
49
+ timestamp: Date.now()
50
+ });
51
+ };
52
+ window.addEventListener("beforeunload", reportStayTime);
53
+ document.addEventListener("visibilitychange", () => {
54
+ if (document.visibilityState === "hidden") reportStayTime();
55
+ else if (document.visibilityState === "visible") {
56
+ this.pageStartTime = Date.now();
57
+ this.clickCount = 0;
58
+ }
59
+ });
60
+ }
61
+ /**
62
+ * 追踪点击行为
63
+ */
64
+ trackClick() {
65
+ document.addEventListener("click", (event) => {
66
+ this.clickCount++;
67
+ const target = event.target;
68
+ const tagName = target.tagName.toLowerCase();
69
+ const elementId = target.id || "";
70
+ const elementClass = target.className || "";
71
+ const elementText = this.getElementText(target);
72
+ const elementPath = this.getElementPath(target);
73
+ if (this.isImportantElement(target)) this.tracker.track("click", {
74
+ tagName,
75
+ elementId,
76
+ elementClass,
77
+ elementText,
78
+ elementPath,
79
+ x: event.clientX,
80
+ y: event.clientY,
81
+ timestamp: Date.now()
82
+ });
83
+ }, true);
84
+ }
85
+ /**
86
+ * 获取元素文本内容
87
+ */
88
+ getElementText(element) {
89
+ return (element.innerText || element.textContent || "").trim().substring(0, 50);
90
+ }
91
+ /**
92
+ * 获取元素路径
93
+ */
94
+ getElementPath(element) {
95
+ const path = [];
96
+ let current = element;
97
+ while (current && current !== document.body) {
98
+ let selector = current.tagName.toLowerCase();
99
+ if (current.id) {
100
+ selector += `#${current.id}`;
101
+ path.unshift(selector);
102
+ break;
103
+ } else if (current.className) {
104
+ const classes = current.className.split(" ").filter((c) => c).join(".");
105
+ if (classes) selector += `.${classes}`;
106
+ }
107
+ path.unshift(selector);
108
+ current = current.parentElement;
109
+ if (path.length >= 5) break;
110
+ }
111
+ return path.join(" > ");
112
+ }
113
+ /**
114
+ * 判断是否为重要元素
115
+ */
116
+ isImportantElement(element) {
117
+ const tagName = element.tagName.toLowerCase();
118
+ if ([
119
+ "a",
120
+ "button",
121
+ "input",
122
+ "select",
123
+ "textarea"
124
+ ].includes(tagName)) return true;
125
+ if (element.onclick || element.getAttribute("onclick")) return true;
126
+ if (element.hasAttribute("data-track") || element.classList.contains("track-click")) return true;
127
+ return false;
128
+ }
129
+ /**
130
+ * 追踪滚动深度
131
+ */
132
+ trackScroll() {
133
+ const handleScroll = throttle(() => {
134
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
135
+ const scrollHeight = document.documentElement.scrollHeight;
136
+ const clientHeight = window.innerHeight;
137
+ const scrollPercent = Math.round(scrollTop / (scrollHeight - clientHeight) * 100);
138
+ if (scrollPercent > this.scrollDepth) {
139
+ this.scrollDepth = scrollPercent;
140
+ if (scrollPercent >= 25 && scrollPercent % 25 === 0) this.tracker.track("scroll_depth", {
141
+ depth: scrollPercent,
142
+ timestamp: Date.now()
143
+ });
144
+ }
145
+ }, 300);
146
+ window.addEventListener("scroll", handleScroll);
147
+ }
148
+ /**
149
+ * 追踪页面可见性
150
+ */
151
+ trackVisibility() {
152
+ document.addEventListener("visibilitychange", () => {
153
+ this.tracker.track("visibility_change", {
154
+ state: document.visibilityState,
155
+ timestamp: Date.now()
156
+ });
157
+ });
158
+ }
159
+ /**
160
+ * 追踪用户参与度
161
+ */
162
+ trackUserEngagement() {
163
+ let inactiveTimer = null;
164
+ const resetInactiveTimer = () => {
165
+ if (inactiveTimer) clearTimeout(inactiveTimer);
166
+ inactiveTimer = setTimeout(() => {
167
+ this.tracker.track("user_inactive", {
168
+ inactiveDuration: 6e4,
169
+ timestamp: Date.now()
170
+ });
171
+ }, 6e4);
172
+ };
173
+ [
174
+ "mousedown",
175
+ "mousemove",
176
+ "keypress",
177
+ "scroll",
178
+ "touchstart"
179
+ ].forEach((event) => {
180
+ document.addEventListener(event, resetInactiveTimer, true);
181
+ });
182
+ resetInactiveTimer();
183
+ }
184
+ /**
185
+ * 追踪表单交互
186
+ */
187
+ trackFormInteraction(formName) {
188
+ return {
189
+ onFocus: () => {
190
+ this.tracker.track("form_start", {
191
+ formName,
192
+ timestamp: Date.now()
193
+ });
194
+ },
195
+ onSubmit: (success, data = {}) => {
196
+ this.tracker.track("form_submit", {
197
+ formName,
198
+ success,
199
+ ...data,
200
+ timestamp: Date.now()
201
+ });
202
+ },
203
+ onAbandon: (fieldName) => {
204
+ this.tracker.track("form_abandon", {
205
+ formName,
206
+ fieldName,
207
+ timestamp: Date.now()
208
+ });
209
+ }
210
+ };
211
+ }
212
+ /**
213
+ * 追踪搜索行为
214
+ */
215
+ trackSearch(keyword, resultCount) {
216
+ this.tracker.track("search", {
217
+ keyword,
218
+ resultCount,
219
+ timestamp: Date.now()
220
+ });
221
+ }
222
+ /**
223
+ * 追踪视频播放
224
+ */
225
+ trackVideo(videoId, action, data = {}) {
226
+ this.tracker.track("video_action", {
227
+ videoId,
228
+ action,
229
+ ...data,
230
+ timestamp: Date.now()
231
+ });
232
+ }
233
+ };
234
+ /**
235
+ * 创建行为监控实例
236
+ */
237
+ function createBehaviorMonitor(tracker) {
238
+ return new BehaviorMonitor(tracker);
239
+ }
240
+ //#endregion
241
+ export { BehaviorMonitor, createBehaviorMonitor };
242
+
243
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Tracker } from '@gctrack/core'\nimport { throttle } from '@gctrack/core'\n\n/**\n * 行为监控插件\n */\nexport class BehaviorMonitor {\n private tracker: Tracker\n private sessionStartTime = Date.now()\n private pageStartTime = Date.now()\n private clickCount = 0\n private scrollDepth = 0\n\n constructor(tracker: Tracker) {\n this.tracker = tracker\n }\n\n /**\n * 启动行为监控\n */\n start(): void {\n if (typeof window === 'undefined') {\n return\n }\n\n this.trackPageView()\n this.trackPageStay()\n this.trackClick()\n this.trackScroll()\n this.trackVisibility()\n this.trackUserEngagement()\n }\n\n /**\n * 追踪页面浏览\n */\n private trackPageView(): void {\n this.tracker.track('page_view', {\n screenWidth: window.screen.width,\n screenHeight: window.screen.height,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n timestamp: Date.now(),\n })\n }\n\n /**\n * 追踪页面停留时间\n */\n private trackPageStay(): void {\n // 页面卸载时上报停留时间\n const reportStayTime = () => {\n const stayTime = Date.now() - this.pageStartTime\n\n this.tracker.track('page_stay', {\n stayTime,\n clickCount: this.clickCount,\n maxScrollDepth: this.scrollDepth,\n timestamp: Date.now(),\n })\n }\n\n window.addEventListener('beforeunload', reportStayTime)\n\n // 页面隐藏时也上报(移动端)\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n reportStayTime()\n }\n else if (document.visibilityState === 'visible') {\n // 页面重新可见时重置计时\n this.pageStartTime = Date.now()\n this.clickCount = 0\n }\n })\n }\n\n /**\n * 追踪点击行为\n */\n private trackClick(): void {\n document.addEventListener(\n 'click',\n (event) => {\n this.clickCount++\n\n const target = event.target as HTMLElement\n const tagName = target.tagName.toLowerCase()\n\n // 获取元素的唯一标识\n const elementId = target.id || ''\n const elementClass = target.className || ''\n const elementText = this.getElementText(target)\n const elementPath = this.getElementPath(target)\n\n // 只上报重要元素的点击\n if (this.isImportantElement(target)) {\n this.tracker.track('click', {\n tagName,\n elementId,\n elementClass,\n elementText,\n elementPath,\n x: event.clientX,\n y: event.clientY,\n timestamp: Date.now(),\n })\n }\n },\n true,\n )\n }\n\n /**\n * 获取元素文本内容\n */\n private getElementText(element: HTMLElement): string {\n const text = element.innerText || element.textContent || ''\n return text.trim().substring(0, 50) // 限制长度\n }\n\n /**\n * 获取元素路径\n */\n private getElementPath(element: HTMLElement): string {\n const path: string[] = []\n let current: HTMLElement | null = element\n\n while (current && current !== document.body) {\n let selector = current.tagName.toLowerCase()\n\n if (current.id) {\n selector += `#${current.id}`\n path.unshift(selector)\n break // ID 是唯一的,可以停止\n }\n else if (current.className) {\n const classes = current.className.split(' ').filter(c => c).join('.')\n if (classes) {\n selector += `.${classes}`\n }\n }\n\n path.unshift(selector)\n current = current.parentElement\n\n // 限制路径深度\n if (path.length >= 5)\n break\n }\n\n return path.join(' > ')\n }\n\n /**\n * 判断是否为重要元素\n */\n private isImportantElement(element: HTMLElement): boolean {\n const tagName = element.tagName.toLowerCase()\n const importantTags = ['a', 'button', 'input', 'select', 'textarea']\n\n // 标签类型判断\n if (importantTags.includes(tagName)) {\n return true\n }\n\n // 带有点击事件的元素\n if ((element as any).onclick || element.getAttribute('onclick')) {\n return true\n }\n\n // 带有特定 class 或 data 属性的元素\n if (\n element.hasAttribute('data-track')\n || element.classList.contains('track-click')\n ) {\n return true\n }\n\n return false\n }\n\n /**\n * 追踪滚动深度\n */\n private trackScroll(): void {\n const handleScroll = throttle(() => {\n const scrollTop = window.pageYOffset || document.documentElement.scrollTop\n const scrollHeight = document.documentElement.scrollHeight\n const clientHeight = window.innerHeight\n\n const scrollPercent = Math.round((scrollTop / (scrollHeight - clientHeight)) * 100)\n\n // 更新最大滚动深度\n if (scrollPercent > this.scrollDepth) {\n this.scrollDepth = scrollPercent\n\n // 每 25% 上报一次\n if (scrollPercent >= 25 && scrollPercent % 25 === 0) {\n this.tracker.track('scroll_depth', {\n depth: scrollPercent,\n timestamp: Date.now(),\n })\n }\n }\n }, 300)\n\n window.addEventListener('scroll', handleScroll)\n }\n\n /**\n * 追踪页面可见性\n */\n private trackVisibility(): void {\n document.addEventListener('visibilitychange', () => {\n this.tracker.track('visibility_change', {\n state: document.visibilityState,\n timestamp: Date.now(),\n })\n })\n }\n\n /**\n * 追踪用户参与度\n */\n private trackUserEngagement(): void {\n let inactiveTimer: ReturnType<typeof setTimeout> | null = null\n\n const resetInactiveTimer = () => {\n if (inactiveTimer) {\n clearTimeout(inactiveTimer)\n }\n\n inactiveTimer = setTimeout(() => {\n this.tracker.track('user_inactive', {\n inactiveDuration: 60000, // 1 分钟\n timestamp: Date.now(),\n })\n }, 60000)\n }\n\n // 监听用户活动\n const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart']\n events.forEach((event) => {\n document.addEventListener(event, resetInactiveTimer, true)\n })\n\n resetInactiveTimer()\n }\n\n /**\n * 追踪表单交互\n */\n trackFormInteraction(formName: string): {\n onFocus: () => void\n onSubmit: (success: boolean, data?: Record<string, any>) => void\n onAbandon: (fieldName: string) => void\n } {\n return {\n // 表单开始填写\n onFocus: () => {\n this.tracker.track('form_start', {\n formName,\n timestamp: Date.now(),\n })\n },\n\n // 表单提交\n onSubmit: (success: boolean, data: Record<string, any> = {}) => {\n this.tracker.track('form_submit', {\n formName,\n success,\n ...data,\n timestamp: Date.now(),\n })\n },\n\n // 表单放弃\n onAbandon: (fieldName: string) => {\n this.tracker.track('form_abandon', {\n formName,\n fieldName,\n timestamp: Date.now(),\n })\n },\n }\n }\n\n /**\n * 追踪搜索行为\n */\n trackSearch(keyword: string, resultCount: number): void {\n this.tracker.track('search', {\n keyword,\n resultCount,\n timestamp: Date.now(),\n })\n }\n\n /**\n * 追踪视频播放\n */\n trackVideo(videoId: string, action: string, data: Record<string, any> = {}): void {\n this.tracker.track('video_action', {\n videoId,\n action, // play, pause, ended, error\n ...data,\n timestamp: Date.now(),\n })\n }\n}\n\n/**\n * 创建行为监控实例\n */\nexport function createBehaviorMonitor(tracker: Tracker): BehaviorMonitor {\n return new BehaviorMonitor(tracker)\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@gctrack/behavior",
3
+ "version": "0.1.0",
4
+ "description": "Behavior monitoring for GCTrack",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "keywords": [
20
+ "behavior",
21
+ "monitoring",
22
+ "user-tracking"
23
+ ],
24
+ "author": "yinuo",
25
+ "license": "MIT",
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "peerDependencies": {
30
+ "@gctrack/core": "0.1.0"
31
+ },
32
+ "scripts": {
33
+ "build": "tsdown",
34
+ "dev": "tsdown --watch"
35
+ }
36
+ }