@gctrack/vue 0.1.2 → 0.2.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/dist/index.cjs CHANGED
@@ -1,44 +1,90 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
1
+
2
2
  //#region src/index.ts
3
3
  /**
4
- * GCTrack Vue 插件对象
4
+ * 运行时探测 Vue2 vs Vue3。
5
+ * Vue2 通过 `Vue.use(plugin)` 传入「构造函数」(typeof === 'function');
6
+ * Vue3 通过 `app.use(plugin)` 传入「应用对象」(typeof === 'object')。
7
+ */
8
+ function isVue2(appOrVue) {
9
+ return typeof appOrVue === "function";
10
+ }
11
+ /**
12
+ * 兼容取组件名:Vue2 `vm.$options.name` / Vue3 `vm.type.name`(Vue3 的 instance 也暴露 $options)。
13
+ */
14
+ function getComponentName(vm) {
15
+ if (!vm) return "Anonymous";
16
+ const name = vm.$options && vm.$options.name || vm.type && vm.type.name;
17
+ return name || "Anonymous";
18
+ }
19
+ /**
20
+ * GCTrack Vue 插件对象(Vue2 / Vue3 通用)
5
21
  */
6
- const GCTrackPlugin = { install(Vue, options) {
22
+ const GCTrackPlugin = { install(appOrVue, options) {
7
23
  const { tracker, router, trackPageView = true, trackErrors = true } = options;
8
- Vue.prototype.$tracker = tracker;
24
+ const v2 = isVue2(appOrVue);
25
+ const config = appOrVue.config;
26
+ if (v2) appOrVue.prototype.$tracker = tracker;
27
+ else config.globalProperties.$tracker = tracker;
9
28
  if (router && trackPageView) router.afterEach((to, from) => {
10
29
  tracker.track("page_view", {
11
30
  from: from.path,
12
31
  to: to.path,
13
- title: to.meta && to.meta.title || document.title,
32
+ title: to.meta && to.meta.title || (typeof document !== "undefined" ? document.title : ""),
14
33
  query: to.query,
15
34
  params: to.params
16
35
  });
17
36
  });
18
- if (trackErrors) Vue.config.errorHandler = (err, vm, info) => {
37
+ if (trackErrors) config.errorHandler = (err, vm, info) => {
19
38
  console.error("Vue Error:", err);
20
39
  tracker.track("vue_error", {
21
40
  message: err.message,
22
41
  stack: err.stack,
23
- componentName: vm && vm.$options && vm.$options.name || "Anonymous",
42
+ componentName: getComponentName(vm),
24
43
  info,
25
44
  timestamp: Date.now()
26
45
  });
27
46
  };
28
- registerDirectives(Vue, tracker);
47
+ registerDirectives(appOrVue, tracker, v2);
29
48
  } };
30
49
  /**
50
+ * 元素 → 清理函数(移除监听 / 断开 observer)。
51
+ * 修复旧实现只有 bind、无 unbind 导致的监听/observer 泄漏。
52
+ */
53
+ const cleanupMap = /* @__PURE__ */ new WeakMap();
54
+ /**
55
+ * 按版本返回正确的指令钩子名(V2 `bind`/`unbind`,V3 `mounted`/`unmounted`),
56
+ * 内部 mount/unmount 逻辑两端共用;unmount 统一执行 cleanupMap 中的清理。
57
+ */
58
+ function versionedDirective(v2, mount) {
59
+ const unmount = (el) => {
60
+ const cleanup = cleanupMap.get(el);
61
+ if (cleanup) {
62
+ cleanup();
63
+ cleanupMap.delete(el);
64
+ }
65
+ };
66
+ return v2 ? {
67
+ bind: mount,
68
+ unbind: unmount
69
+ } : {
70
+ mounted: mount,
71
+ unmounted: unmount
72
+ };
73
+ }
74
+ /**
31
75
  * 注册全局指令
32
76
  */
33
- function registerDirectives(Vue, tracker) {
34
- Vue.directive("track", { bind(el, binding) {
35
- el.addEventListener("click", () => {
77
+ function registerDirectives(appOrVue, tracker, v2) {
78
+ appOrVue.directive("track", versionedDirective(v2, (el, binding) => {
79
+ const handler = () => {
36
80
  const eventName = binding.value;
37
81
  const eventData = binding.arg ? { [binding.arg]: binding.modifiers } : {};
38
82
  tracker.track(eventName, eventData);
39
- });
40
- } });
41
- Vue.directive("track-view", { bind(el, binding) {
83
+ };
84
+ el.addEventListener("click", handler);
85
+ cleanupMap.set(el, () => el.removeEventListener("click", handler));
86
+ }));
87
+ appOrVue.directive("track-view", versionedDirective(v2, (el, binding) => {
42
88
  if (typeof IntersectionObserver === "undefined") return;
43
89
  const observer = new IntersectionObserver((entries) => {
44
90
  entries.forEach((entry) => {
@@ -50,11 +96,12 @@ function registerDirectives(Vue, tracker) {
50
96
  });
51
97
  });
52
98
  observer.observe(el);
53
- } });
54
- Vue.directive("track-stay", { bind(el, binding) {
99
+ cleanupMap.set(el, () => observer.disconnect());
100
+ }));
101
+ appOrVue.directive("track-stay", versionedDirective(v2, (el, binding) => {
55
102
  if (typeof IntersectionObserver === "undefined") return;
56
103
  const startTime = Date.now();
57
- new IntersectionObserver((entries) => {
104
+ const observer = new IntersectionObserver((entries) => {
58
105
  entries.forEach((entry) => {
59
106
  if (!entry.isIntersecting) {
60
107
  const stayTime = Date.now() - startTime;
@@ -62,28 +109,24 @@ function registerDirectives(Vue, tracker) {
62
109
  tracker.track(`${eventName}_stay`, { stayTime });
63
110
  }
64
111
  });
65
- }).observe(el);
66
- } });
112
+ });
113
+ observer.observe(el);
114
+ cleanupMap.set(el, () => observer.disconnect());
115
+ }));
67
116
  }
68
117
  /**
69
118
  * Vue Mixin
70
119
  */
71
120
  const GCTrackMixin = { methods: {
72
- /**
73
- * 追踪事件
74
- */
75
121
  $track(eventType, data) {
76
122
  if (this.$tracker) this.$tracker.track(eventType, data);
77
123
  },
78
- /**
79
- * 追踪页面浏览
80
- */
81
124
  $trackPageView(data) {
82
125
  if (this.$tracker) this.$tracker.track("page_view", data);
83
126
  }
84
127
  } };
128
+
85
129
  //#endregion
86
130
  exports.GCTrackMixin = GCTrackMixin;
87
131
  exports.GCTrackPlugin = GCTrackPlugin;
88
-
89
132
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Tracker } from '@gctrack/core'\n\n/**\n * Vue 插件选项\n */\nexport interface VuePluginOptions {\n tracker: Tracker\n router?: any\n trackPageView?: boolean\n trackErrors?: boolean\n}\n\n/**\n * GCTrack Vue 插件对象\n */\nexport const GCTrackPlugin = {\n install(Vue: any, options: VuePluginOptions): void {\n const { tracker, router, trackPageView = true, trackErrors = true } = options\n\n // tracker 挂载到 Vue 原型\n Vue.prototype.$tracker = tracker\n\n // 路由变化时追踪页面浏览\n if (router && trackPageView) {\n router.afterEach((to: any, from: any) => {\n tracker.track('page_view', {\n from: from.path,\n to: to.path,\n title: (to.meta && to.meta.title) || document.title,\n query: to.query,\n params: to.params,\n })\n })\n }\n\n // 全局错误处理\n if (trackErrors) {\n Vue.config.errorHandler = (err: Error, vm: any, info: string) => {\n console.error('Vue Error:', err)\n\n tracker.track('vue_error', {\n message: err.message,\n stack: err.stack,\n componentName: (vm && vm.$options && vm.$options.name) || 'Anonymous',\n info,\n timestamp: Date.now(),\n })\n }\n }\n\n // 注册全局指令\n registerDirectives(Vue, tracker)\n },\n}\n\n/**\n * 注册全局指令\n */\nfunction registerDirectives(Vue: any, tracker: Tracker) {\n // 点击埋点指令\n Vue.directive('track', {\n bind(el: HTMLElement, binding: any) {\n el.addEventListener('click', () => {\n const eventName = binding.value\n const eventData = binding.arg ? { [binding.arg]: binding.modifiers } : {}\n\n tracker.track(eventName, eventData)\n })\n },\n })\n\n // 曝光埋点指令\n Vue.directive('track-view', {\n bind(el: HTMLElement, binding: any) {\n if (typeof IntersectionObserver === 'undefined') {\n return\n }\n\n const observer = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n const eventName = binding.value\n tracker.track(`${eventName}_view`, {\n element: el.tagName,\n })\n\n // 只上报一次\n observer.unobserve(el)\n }\n })\n })\n\n observer.observe(el)\n },\n })\n\n // 停留时长埋点指令\n Vue.directive('track-stay', {\n bind(el: HTMLElement, binding: any) {\n if (typeof IntersectionObserver === 'undefined') {\n return\n }\n\n const startTime = Date.now()\n\n const observer = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if (!entry.isIntersecting) {\n const stayTime = Date.now() - startTime\n const eventName = binding.value\n\n tracker.track(`${eventName}_stay`, {\n stayTime,\n })\n }\n })\n })\n\n observer.observe(el)\n },\n })\n}\n\n/**\n * Vue Mixin\n */\nexport const GCTrackMixin = {\n methods: {\n /**\n * 追踪事件\n */\n $track(eventType: string, data?: Record<string, any>): void {\n if (this.$tracker) {\n this.$tracker.track(eventType, data)\n }\n },\n\n /**\n * 追踪页面浏览\n */\n $trackPageView(data?: Record<string, any>): void {\n if (this.$tracker) {\n this.$tracker.track('page_view', data)\n }\n },\n },\n}\n\n/**\n * 类型声明\n */\ndeclare module 'vue/types/vue' {\n interface Vue {\n $tracker: Tracker\n $track: (eventType: string, data?: Record<string, any>) => void\n $trackPageView: (data?: Record<string, any>) => void\n }\n}\n"],"mappings":";;;;;AAeA,MAAa,gBAAgB,EAC3B,QAAQ,KAAU,SAAiC;CACjD,MAAM,EAAE,SAAS,QAAQ,gBAAgB,MAAM,cAAc,SAAS;CAGtE,IAAI,UAAU,WAAW;CAGzB,IAAI,UAAU,eACZ,OAAO,WAAW,IAAS,SAAc;EACvC,QAAQ,MAAM,aAAa;GACzB,MAAM,KAAK;GACX,IAAI,GAAG;GACP,OAAQ,GAAG,QAAQ,GAAG,KAAK,SAAU,SAAS;GAC9C,OAAO,GAAG;GACV,QAAQ,GAAG;GACZ,CAAC;GACF;CAIJ,IAAI,aACF,IAAI,OAAO,gBAAgB,KAAY,IAAS,SAAiB;EAC/D,QAAQ,MAAM,cAAc,IAAI;EAEhC,QAAQ,MAAM,aAAa;GACzB,SAAS,IAAI;GACb,OAAO,IAAI;GACX,eAAgB,MAAM,GAAG,YAAY,GAAG,SAAS,QAAS;GAC1D;GACA,WAAW,KAAK,KAAK;GACtB,CAAC;;CAKN,mBAAmB,KAAK,QAAQ;GAEnC;;;;AAKD,SAAS,mBAAmB,KAAU,SAAkB;CAEtD,IAAI,UAAU,SAAS,EACrB,KAAK,IAAiB,SAAc;EAClC,GAAG,iBAAiB,eAAe;GACjC,MAAM,YAAY,QAAQ;GAC1B,MAAM,YAAY,QAAQ,MAAM,GAAG,QAAQ,MAAM,QAAQ,WAAW,GAAG,EAAE;GAEzE,QAAQ,MAAM,WAAW,UAAU;IACnC;IAEL,CAAC;CAGF,IAAI,UAAU,cAAc,EAC1B,KAAK,IAAiB,SAAc;EAClC,IAAI,OAAO,yBAAyB,aAClC;EAGF,MAAM,WAAW,IAAI,sBAAsB,YAAY;GACrD,QAAQ,SAAS,UAAU;IACzB,IAAI,MAAM,gBAAgB;KACxB,MAAM,YAAY,QAAQ;KAC1B,QAAQ,MAAM,GAAG,UAAU,QAAQ,EACjC,SAAS,GAAG,SACb,CAAC;KAGF,SAAS,UAAU,GAAG;;KAExB;IACF;EAEF,SAAS,QAAQ,GAAG;IAEvB,CAAC;CAGF,IAAI,UAAU,cAAc,EAC1B,KAAK,IAAiB,SAAc;EAClC,IAAI,OAAO,yBAAyB,aAClC;EAGF,MAAM,YAAY,KAAK,KAAK;EAe5B,IAbqB,sBAAsB,YAAY;GACrD,QAAQ,SAAS,UAAU;IACzB,IAAI,CAAC,MAAM,gBAAgB;KACzB,MAAM,WAAW,KAAK,KAAK,GAAG;KAC9B,MAAM,YAAY,QAAQ;KAE1B,QAAQ,MAAM,GAAG,UAAU,QAAQ,EACjC,UACD,CAAC;;KAEJ;IAGI,CAAC,QAAQ,GAAG;IAEvB,CAAC;;;;;AAMJ,MAAa,eAAe,EAC1B,SAAS;;;;CAIP,OAAO,WAAmB,MAAkC;EAC1D,IAAI,KAAK,UACP,KAAK,SAAS,MAAM,WAAW,KAAK;;;;;CAOxC,eAAe,MAAkC;EAC/C,IAAI,KAAK,UACP,KAAK,SAAS,MAAM,aAAa,KAAK;;CAG3C,EACF"}
1
+ {"version":3,"file":"index.cjs","names":["appOrVue: any","vm: any","options: VuePluginOptions","to: any","from: any","err: Error","info: string","v2: boolean","mount: (el: HTMLElement, binding: any) => void","el: HTMLElement","tracker: Tracker","binding: any","eventType: string","data?: Record<string, any>"],"sources":["../src/index.ts"],"sourcesContent":["import type { Tracker } from '@gctrack/core'\n\n/**\n * Vue 插件选项\n */\nexport interface VuePluginOptions {\n tracker: Tracker\n router?: any\n trackPageView?: boolean\n trackErrors?: boolean\n}\n\n/**\n * 运行时探测 Vue2 vs Vue3。\n * Vue2 通过 `Vue.use(plugin)` 传入「构造函数」(typeof === 'function');\n * Vue3 通过 `app.use(plugin)` 传入「应用对象」(typeof === 'object')。\n */\nfunction isVue2(appOrVue: any): boolean {\n return typeof appOrVue === 'function'\n}\n\n/**\n * 兼容取组件名:Vue2 `vm.$options.name` / Vue3 `vm.type.name`(Vue3 的 instance 也暴露 $options)。\n */\nfunction getComponentName(vm: any): string {\n if (!vm) return 'Anonymous'\n const name = (vm.$options && vm.$options.name) || (vm.type && vm.type.name)\n return name || 'Anonymous'\n}\n\n/**\n * GCTrack Vue 插件对象(Vue2 / Vue3 通用)\n */\nexport const GCTrackPlugin = {\n install(appOrVue: any, options: VuePluginOptions): void {\n const { tracker, router, trackPageView = true, trackErrors = true } = options\n const v2 = isVue2(appOrVue)\n const config = appOrVue.config\n\n // 全局属性:V2 prototype / V3 挂 globalProperties\n if (v2) {\n appOrVue.prototype.$tracker = tracker\n } else {\n config.globalProperties.$tracker = tracker\n }\n\n // 路由变化时追踪页面浏览(vue-router 3/4 均提供 afterEach)\n if (router && trackPageView) {\n router.afterEach((to: any, from: any) => {\n tracker.track('page_view', {\n from: from.path,\n to: to.path,\n title: (to.meta && to.meta.title) || (typeof document !== 'undefined' ? document.title : ''),\n query: to.query,\n params: to.params,\n })\n })\n }\n\n // 全局错误处理(两端均挂 .config.errorHandler)\n if (trackErrors) {\n config.errorHandler = (err: Error, vm: any, info: string) => {\n console.error('Vue Error:', err)\n\n tracker.track('vue_error', {\n message: err.message,\n stack: err.stack,\n componentName: getComponentName(vm),\n info,\n timestamp: Date.now(),\n })\n }\n }\n\n // 注册全局指令(Vue2/3 都有 .directive,接收者已正确)\n registerDirectives(appOrVue, tracker, v2)\n },\n}\n\n/**\n * 元素 → 清理函数(移除监听 / 断开 observer)。\n * 修复旧实现只有 bind、无 unbind 导致的监听/observer 泄漏。\n */\nconst cleanupMap = new WeakMap<HTMLElement, () => void>()\n\n/**\n * 按版本返回正确的指令钩子名(V2 `bind`/`unbind`,V3 `mounted`/`unmounted`),\n * 内部 mount/unmount 逻辑两端共用;unmount 统一执行 cleanupMap 中的清理。\n */\nfunction versionedDirective(\n v2: boolean,\n mount: (el: HTMLElement, binding: any) => void,\n): any {\n const unmount = (el: HTMLElement) => {\n const cleanup = cleanupMap.get(el)\n if (cleanup) {\n cleanup()\n cleanupMap.delete(el)\n }\n }\n return v2 ? { bind: mount, unbind: unmount } : { mounted: mount, unmounted: unmount }\n}\n\n/**\n * 注册全局指令\n */\nfunction registerDirectives(appOrVue: any, tracker: Tracker, v2: boolean): void {\n // 点击埋点指令\n appOrVue.directive(\n 'track',\n versionedDirective(v2, (el: HTMLElement, binding: any) => {\n const handler = () => {\n const eventName = binding.value\n const eventData = binding.arg ? { [binding.arg]: binding.modifiers } : {}\n tracker.track(eventName, eventData)\n }\n el.addEventListener('click', handler)\n cleanupMap.set(el, () => el.removeEventListener('click', handler))\n }),\n )\n\n // 曝光埋点指令\n appOrVue.directive(\n 'track-view',\n versionedDirective(v2, (el: HTMLElement, binding: any) => {\n if (typeof IntersectionObserver === 'undefined') {\n return\n }\n\n const observer = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n const eventName = binding.value\n tracker.track(`${eventName}_view`, {\n element: el.tagName,\n })\n // 只上报一次\n observer.unobserve(el)\n }\n })\n })\n\n observer.observe(el)\n cleanupMap.set(el, () => observer.disconnect())\n }),\n )\n\n // 停留时长埋点指令\n appOrVue.directive(\n 'track-stay',\n versionedDirective(v2, (el: HTMLElement, binding: any) => {\n if (typeof IntersectionObserver === 'undefined') {\n return\n }\n\n const startTime = Date.now()\n\n const observer = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if (!entry.isIntersecting) {\n const stayTime = Date.now() - startTime\n const eventName = binding.value\n\n tracker.track(`${eventName}_stay`, {\n stayTime,\n })\n }\n })\n })\n\n observer.observe(el)\n cleanupMap.set(el, () => observer.disconnect())\n }),\n )\n}\n\n/**\n * Vue Mixin\n */\nexport const GCTrackMixin = {\n methods: {\n /**\n * 追踪事件\n */\n $track(this: any, eventType: string, data?: Record<string, any>): void {\n if (this.$tracker) {\n this.$tracker.track(eventType, data)\n }\n },\n\n /**\n * 追踪页面浏览\n */\n $trackPageView(this: any, data?: Record<string, any>): void {\n if (this.$tracker) {\n this.$tracker.track('page_view', data)\n }\n },\n },\n}\n\n/**\n * 类型声明(Vue2 / Vue3 双端增强)\n */\n// @ts-ignore vue@3 无 vue/types/vue 子路径;此处增强对 Vue2 消费者侧仍生效,vue@3 构建时压制报错\ndeclare module 'vue/types/vue' {\n interface Vue {\n $tracker: Tracker\n $track: (eventType: string, data?: Record<string, any>) => void\n $trackPageView: (data?: Record<string, any>) => void\n }\n}\n\ndeclare module 'vue' {\n interface ComponentCustomProperties {\n $tracker: Tracker\n $track: (eventType: string, data?: Record<string, any>) => void\n $trackPageView: (data?: Record<string, any>) => void\n }\n}\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -5,10 +5,10 @@ export interface VuePluginOptions {
5
5
  trackPageView?: boolean;
6
6
  trackErrors?: boolean;
7
7
  }
8
- export declare const GCTrackPlugin: {install(Vue: any, options: VuePluginOptions): void};
8
+ export declare const GCTrackPlugin: {install(appOrVue: any, options: VuePluginOptions): void};
9
9
  export declare const GCTrackMixin: {methods: {
10
- $track(eventType: string, data?: Record<string, any>): void;
11
- $trackPageView(data?: Record<string, any>): void;
10
+ $track(this: any, eventType: string, data?: Record<string, any>): void;
11
+ $trackPageView(this: any, data?: Record<string, any>): void;
12
12
  }};
13
13
  declare module "vue/types/vue" {
14
14
  interface Vue {
@@ -17,3 +17,10 @@ declare module "vue/types/vue" {
17
17
  $trackPageView: (data?: Record<string, any>) => void;
18
18
  }
19
19
  }
20
+ declare module "vue" {
21
+ interface ComponentCustomProperties {
22
+ $tracker: Tracker;
23
+ $track: (eventType: string, data?: Record<string, any>) => void;
24
+ $trackPageView: (data?: Record<string, any>) => void;
25
+ }
26
+ }
package/dist/index.d.ts CHANGED
@@ -5,10 +5,10 @@ export interface VuePluginOptions {
5
5
  trackPageView?: boolean;
6
6
  trackErrors?: boolean;
7
7
  }
8
- export declare const GCTrackPlugin: {install(Vue: any, options: VuePluginOptions): void};
8
+ export declare const GCTrackPlugin: {install(appOrVue: any, options: VuePluginOptions): void};
9
9
  export declare const GCTrackMixin: {methods: {
10
- $track(eventType: string, data?: Record<string, any>): void;
11
- $trackPageView(data?: Record<string, any>): void;
10
+ $track(this: any, eventType: string, data?: Record<string, any>): void;
11
+ $trackPageView(this: any, data?: Record<string, any>): void;
12
12
  }};
13
13
  declare module "vue/types/vue" {
14
14
  interface Vue {
@@ -17,3 +17,10 @@ declare module "vue/types/vue" {
17
17
  $trackPageView: (data?: Record<string, any>) => void;
18
18
  }
19
19
  }
20
+ declare module "vue" {
21
+ interface ComponentCustomProperties {
22
+ $tracker: Tracker;
23
+ $track: (eventType: string, data?: Record<string, any>) => void;
24
+ $trackPageView: (data?: Record<string, any>) => void;
25
+ }
26
+ }
package/dist/index.js CHANGED
@@ -1,43 +1,89 @@
1
1
  //#region src/index.ts
2
2
  /**
3
- * GCTrack Vue 插件对象
3
+ * 运行时探测 Vue2 vs Vue3。
4
+ * Vue2 通过 `Vue.use(plugin)` 传入「构造函数」(typeof === 'function');
5
+ * Vue3 通过 `app.use(plugin)` 传入「应用对象」(typeof === 'object')。
4
6
  */
5
- const GCTrackPlugin = { install(Vue, options) {
7
+ function isVue2(appOrVue) {
8
+ return typeof appOrVue === "function";
9
+ }
10
+ /**
11
+ * 兼容取组件名:Vue2 `vm.$options.name` / Vue3 `vm.type.name`(Vue3 的 instance 也暴露 $options)。
12
+ */
13
+ function getComponentName(vm) {
14
+ if (!vm) return "Anonymous";
15
+ const name = vm.$options && vm.$options.name || vm.type && vm.type.name;
16
+ return name || "Anonymous";
17
+ }
18
+ /**
19
+ * GCTrack Vue 插件对象(Vue2 / Vue3 通用)
20
+ */
21
+ const GCTrackPlugin = { install(appOrVue, options) {
6
22
  const { tracker, router, trackPageView = true, trackErrors = true } = options;
7
- Vue.prototype.$tracker = tracker;
23
+ const v2 = isVue2(appOrVue);
24
+ const config = appOrVue.config;
25
+ if (v2) appOrVue.prototype.$tracker = tracker;
26
+ else config.globalProperties.$tracker = tracker;
8
27
  if (router && trackPageView) router.afterEach((to, from) => {
9
28
  tracker.track("page_view", {
10
29
  from: from.path,
11
30
  to: to.path,
12
- title: to.meta && to.meta.title || document.title,
31
+ title: to.meta && to.meta.title || (typeof document !== "undefined" ? document.title : ""),
13
32
  query: to.query,
14
33
  params: to.params
15
34
  });
16
35
  });
17
- if (trackErrors) Vue.config.errorHandler = (err, vm, info) => {
36
+ if (trackErrors) config.errorHandler = (err, vm, info) => {
18
37
  console.error("Vue Error:", err);
19
38
  tracker.track("vue_error", {
20
39
  message: err.message,
21
40
  stack: err.stack,
22
- componentName: vm && vm.$options && vm.$options.name || "Anonymous",
41
+ componentName: getComponentName(vm),
23
42
  info,
24
43
  timestamp: Date.now()
25
44
  });
26
45
  };
27
- registerDirectives(Vue, tracker);
46
+ registerDirectives(appOrVue, tracker, v2);
28
47
  } };
29
48
  /**
49
+ * 元素 → 清理函数(移除监听 / 断开 observer)。
50
+ * 修复旧实现只有 bind、无 unbind 导致的监听/observer 泄漏。
51
+ */
52
+ const cleanupMap = /* @__PURE__ */ new WeakMap();
53
+ /**
54
+ * 按版本返回正确的指令钩子名(V2 `bind`/`unbind`,V3 `mounted`/`unmounted`),
55
+ * 内部 mount/unmount 逻辑两端共用;unmount 统一执行 cleanupMap 中的清理。
56
+ */
57
+ function versionedDirective(v2, mount) {
58
+ const unmount = (el) => {
59
+ const cleanup = cleanupMap.get(el);
60
+ if (cleanup) {
61
+ cleanup();
62
+ cleanupMap.delete(el);
63
+ }
64
+ };
65
+ return v2 ? {
66
+ bind: mount,
67
+ unbind: unmount
68
+ } : {
69
+ mounted: mount,
70
+ unmounted: unmount
71
+ };
72
+ }
73
+ /**
30
74
  * 注册全局指令
31
75
  */
32
- function registerDirectives(Vue, tracker) {
33
- Vue.directive("track", { bind(el, binding) {
34
- el.addEventListener("click", () => {
76
+ function registerDirectives(appOrVue, tracker, v2) {
77
+ appOrVue.directive("track", versionedDirective(v2, (el, binding) => {
78
+ const handler = () => {
35
79
  const eventName = binding.value;
36
80
  const eventData = binding.arg ? { [binding.arg]: binding.modifiers } : {};
37
81
  tracker.track(eventName, eventData);
38
- });
39
- } });
40
- Vue.directive("track-view", { bind(el, binding) {
82
+ };
83
+ el.addEventListener("click", handler);
84
+ cleanupMap.set(el, () => el.removeEventListener("click", handler));
85
+ }));
86
+ appOrVue.directive("track-view", versionedDirective(v2, (el, binding) => {
41
87
  if (typeof IntersectionObserver === "undefined") return;
42
88
  const observer = new IntersectionObserver((entries) => {
43
89
  entries.forEach((entry) => {
@@ -49,11 +95,12 @@ function registerDirectives(Vue, tracker) {
49
95
  });
50
96
  });
51
97
  observer.observe(el);
52
- } });
53
- Vue.directive("track-stay", { bind(el, binding) {
98
+ cleanupMap.set(el, () => observer.disconnect());
99
+ }));
100
+ appOrVue.directive("track-stay", versionedDirective(v2, (el, binding) => {
54
101
  if (typeof IntersectionObserver === "undefined") return;
55
102
  const startTime = Date.now();
56
- new IntersectionObserver((entries) => {
103
+ const observer = new IntersectionObserver((entries) => {
57
104
  entries.forEach((entry) => {
58
105
  if (!entry.isIntersecting) {
59
106
  const stayTime = Date.now() - startTime;
@@ -61,27 +108,23 @@ function registerDirectives(Vue, tracker) {
61
108
  tracker.track(`${eventName}_stay`, { stayTime });
62
109
  }
63
110
  });
64
- }).observe(el);
65
- } });
111
+ });
112
+ observer.observe(el);
113
+ cleanupMap.set(el, () => observer.disconnect());
114
+ }));
66
115
  }
67
116
  /**
68
117
  * Vue Mixin
69
118
  */
70
119
  const GCTrackMixin = { methods: {
71
- /**
72
- * 追踪事件
73
- */
74
120
  $track(eventType, data) {
75
121
  if (this.$tracker) this.$tracker.track(eventType, data);
76
122
  },
77
- /**
78
- * 追踪页面浏览
79
- */
80
123
  $trackPageView(data) {
81
124
  if (this.$tracker) this.$tracker.track("page_view", data);
82
125
  }
83
126
  } };
127
+
84
128
  //#endregion
85
129
  export { GCTrackMixin, GCTrackPlugin };
86
-
87
130
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Tracker } from '@gctrack/core'\n\n/**\n * Vue 插件选项\n */\nexport interface VuePluginOptions {\n tracker: Tracker\n router?: any\n trackPageView?: boolean\n trackErrors?: boolean\n}\n\n/**\n * GCTrack Vue 插件对象\n */\nexport const GCTrackPlugin = {\n install(Vue: any, options: VuePluginOptions): void {\n const { tracker, router, trackPageView = true, trackErrors = true } = options\n\n // tracker 挂载到 Vue 原型\n Vue.prototype.$tracker = tracker\n\n // 路由变化时追踪页面浏览\n if (router && trackPageView) {\n router.afterEach((to: any, from: any) => {\n tracker.track('page_view', {\n from: from.path,\n to: to.path,\n title: (to.meta && to.meta.title) || document.title,\n query: to.query,\n params: to.params,\n })\n })\n }\n\n // 全局错误处理\n if (trackErrors) {\n Vue.config.errorHandler = (err: Error, vm: any, info: string) => {\n console.error('Vue Error:', err)\n\n tracker.track('vue_error', {\n message: err.message,\n stack: err.stack,\n componentName: (vm && vm.$options && vm.$options.name) || 'Anonymous',\n info,\n timestamp: Date.now(),\n })\n }\n }\n\n // 注册全局指令\n registerDirectives(Vue, tracker)\n },\n}\n\n/**\n * 注册全局指令\n */\nfunction registerDirectives(Vue: any, tracker: Tracker) {\n // 点击埋点指令\n Vue.directive('track', {\n bind(el: HTMLElement, binding: any) {\n el.addEventListener('click', () => {\n const eventName = binding.value\n const eventData = binding.arg ? { [binding.arg]: binding.modifiers } : {}\n\n tracker.track(eventName, eventData)\n })\n },\n })\n\n // 曝光埋点指令\n Vue.directive('track-view', {\n bind(el: HTMLElement, binding: any) {\n if (typeof IntersectionObserver === 'undefined') {\n return\n }\n\n const observer = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n const eventName = binding.value\n tracker.track(`${eventName}_view`, {\n element: el.tagName,\n })\n\n // 只上报一次\n observer.unobserve(el)\n }\n })\n })\n\n observer.observe(el)\n },\n })\n\n // 停留时长埋点指令\n Vue.directive('track-stay', {\n bind(el: HTMLElement, binding: any) {\n if (typeof IntersectionObserver === 'undefined') {\n return\n }\n\n const startTime = Date.now()\n\n const observer = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if (!entry.isIntersecting) {\n const stayTime = Date.now() - startTime\n const eventName = binding.value\n\n tracker.track(`${eventName}_stay`, {\n stayTime,\n })\n }\n })\n })\n\n observer.observe(el)\n },\n })\n}\n\n/**\n * Vue Mixin\n */\nexport const GCTrackMixin = {\n methods: {\n /**\n * 追踪事件\n */\n $track(eventType: string, data?: Record<string, any>): void {\n if (this.$tracker) {\n this.$tracker.track(eventType, data)\n }\n },\n\n /**\n * 追踪页面浏览\n */\n $trackPageView(data?: Record<string, any>): void {\n if (this.$tracker) {\n this.$tracker.track('page_view', data)\n }\n },\n },\n}\n\n/**\n * 类型声明\n */\ndeclare module 'vue/types/vue' {\n interface Vue {\n $tracker: Tracker\n $track: (eventType: string, data?: Record<string, any>) => void\n $trackPageView: (data?: Record<string, any>) => void\n }\n}\n"],"mappings":";;;;AAeA,MAAa,gBAAgB,EAC3B,QAAQ,KAAU,SAAiC;CACjD,MAAM,EAAE,SAAS,QAAQ,gBAAgB,MAAM,cAAc,SAAS;CAGtE,IAAI,UAAU,WAAW;CAGzB,IAAI,UAAU,eACZ,OAAO,WAAW,IAAS,SAAc;EACvC,QAAQ,MAAM,aAAa;GACzB,MAAM,KAAK;GACX,IAAI,GAAG;GACP,OAAQ,GAAG,QAAQ,GAAG,KAAK,SAAU,SAAS;GAC9C,OAAO,GAAG;GACV,QAAQ,GAAG;GACZ,CAAC;GACF;CAIJ,IAAI,aACF,IAAI,OAAO,gBAAgB,KAAY,IAAS,SAAiB;EAC/D,QAAQ,MAAM,cAAc,IAAI;EAEhC,QAAQ,MAAM,aAAa;GACzB,SAAS,IAAI;GACb,OAAO,IAAI;GACX,eAAgB,MAAM,GAAG,YAAY,GAAG,SAAS,QAAS;GAC1D;GACA,WAAW,KAAK,KAAK;GACtB,CAAC;;CAKN,mBAAmB,KAAK,QAAQ;GAEnC;;;;AAKD,SAAS,mBAAmB,KAAU,SAAkB;CAEtD,IAAI,UAAU,SAAS,EACrB,KAAK,IAAiB,SAAc;EAClC,GAAG,iBAAiB,eAAe;GACjC,MAAM,YAAY,QAAQ;GAC1B,MAAM,YAAY,QAAQ,MAAM,GAAG,QAAQ,MAAM,QAAQ,WAAW,GAAG,EAAE;GAEzE,QAAQ,MAAM,WAAW,UAAU;IACnC;IAEL,CAAC;CAGF,IAAI,UAAU,cAAc,EAC1B,KAAK,IAAiB,SAAc;EAClC,IAAI,OAAO,yBAAyB,aAClC;EAGF,MAAM,WAAW,IAAI,sBAAsB,YAAY;GACrD,QAAQ,SAAS,UAAU;IACzB,IAAI,MAAM,gBAAgB;KACxB,MAAM,YAAY,QAAQ;KAC1B,QAAQ,MAAM,GAAG,UAAU,QAAQ,EACjC,SAAS,GAAG,SACb,CAAC;KAGF,SAAS,UAAU,GAAG;;KAExB;IACF;EAEF,SAAS,QAAQ,GAAG;IAEvB,CAAC;CAGF,IAAI,UAAU,cAAc,EAC1B,KAAK,IAAiB,SAAc;EAClC,IAAI,OAAO,yBAAyB,aAClC;EAGF,MAAM,YAAY,KAAK,KAAK;EAe5B,IAbqB,sBAAsB,YAAY;GACrD,QAAQ,SAAS,UAAU;IACzB,IAAI,CAAC,MAAM,gBAAgB;KACzB,MAAM,WAAW,KAAK,KAAK,GAAG;KAC9B,MAAM,YAAY,QAAQ;KAE1B,QAAQ,MAAM,GAAG,UAAU,QAAQ,EACjC,UACD,CAAC;;KAEJ;IAGI,CAAC,QAAQ,GAAG;IAEvB,CAAC;;;;;AAMJ,MAAa,eAAe,EAC1B,SAAS;;;;CAIP,OAAO,WAAmB,MAAkC;EAC1D,IAAI,KAAK,UACP,KAAK,SAAS,MAAM,WAAW,KAAK;;;;;CAOxC,eAAe,MAAkC;EAC/C,IAAI,KAAK,UACP,KAAK,SAAS,MAAM,aAAa,KAAK;;CAG3C,EACF"}
1
+ {"version":3,"file":"index.js","names":["appOrVue: any","vm: any","options: VuePluginOptions","to: any","from: any","err: Error","info: string","v2: boolean","mount: (el: HTMLElement, binding: any) => void","el: HTMLElement","tracker: Tracker","binding: any","eventType: string","data?: Record<string, any>"],"sources":["../src/index.ts"],"sourcesContent":["import type { Tracker } from '@gctrack/core'\n\n/**\n * Vue 插件选项\n */\nexport interface VuePluginOptions {\n tracker: Tracker\n router?: any\n trackPageView?: boolean\n trackErrors?: boolean\n}\n\n/**\n * 运行时探测 Vue2 vs Vue3。\n * Vue2 通过 `Vue.use(plugin)` 传入「构造函数」(typeof === 'function');\n * Vue3 通过 `app.use(plugin)` 传入「应用对象」(typeof === 'object')。\n */\nfunction isVue2(appOrVue: any): boolean {\n return typeof appOrVue === 'function'\n}\n\n/**\n * 兼容取组件名:Vue2 `vm.$options.name` / Vue3 `vm.type.name`(Vue3 的 instance 也暴露 $options)。\n */\nfunction getComponentName(vm: any): string {\n if (!vm) return 'Anonymous'\n const name = (vm.$options && vm.$options.name) || (vm.type && vm.type.name)\n return name || 'Anonymous'\n}\n\n/**\n * GCTrack Vue 插件对象(Vue2 / Vue3 通用)\n */\nexport const GCTrackPlugin = {\n install(appOrVue: any, options: VuePluginOptions): void {\n const { tracker, router, trackPageView = true, trackErrors = true } = options\n const v2 = isVue2(appOrVue)\n const config = appOrVue.config\n\n // 全局属性:V2 prototype / V3 挂 globalProperties\n if (v2) {\n appOrVue.prototype.$tracker = tracker\n } else {\n config.globalProperties.$tracker = tracker\n }\n\n // 路由变化时追踪页面浏览(vue-router 3/4 均提供 afterEach)\n if (router && trackPageView) {\n router.afterEach((to: any, from: any) => {\n tracker.track('page_view', {\n from: from.path,\n to: to.path,\n title: (to.meta && to.meta.title) || (typeof document !== 'undefined' ? document.title : ''),\n query: to.query,\n params: to.params,\n })\n })\n }\n\n // 全局错误处理(两端均挂 .config.errorHandler)\n if (trackErrors) {\n config.errorHandler = (err: Error, vm: any, info: string) => {\n console.error('Vue Error:', err)\n\n tracker.track('vue_error', {\n message: err.message,\n stack: err.stack,\n componentName: getComponentName(vm),\n info,\n timestamp: Date.now(),\n })\n }\n }\n\n // 注册全局指令(Vue2/3 都有 .directive,接收者已正确)\n registerDirectives(appOrVue, tracker, v2)\n },\n}\n\n/**\n * 元素 → 清理函数(移除监听 / 断开 observer)。\n * 修复旧实现只有 bind、无 unbind 导致的监听/observer 泄漏。\n */\nconst cleanupMap = new WeakMap<HTMLElement, () => void>()\n\n/**\n * 按版本返回正确的指令钩子名(V2 `bind`/`unbind`,V3 `mounted`/`unmounted`),\n * 内部 mount/unmount 逻辑两端共用;unmount 统一执行 cleanupMap 中的清理。\n */\nfunction versionedDirective(\n v2: boolean,\n mount: (el: HTMLElement, binding: any) => void,\n): any {\n const unmount = (el: HTMLElement) => {\n const cleanup = cleanupMap.get(el)\n if (cleanup) {\n cleanup()\n cleanupMap.delete(el)\n }\n }\n return v2 ? { bind: mount, unbind: unmount } : { mounted: mount, unmounted: unmount }\n}\n\n/**\n * 注册全局指令\n */\nfunction registerDirectives(appOrVue: any, tracker: Tracker, v2: boolean): void {\n // 点击埋点指令\n appOrVue.directive(\n 'track',\n versionedDirective(v2, (el: HTMLElement, binding: any) => {\n const handler = () => {\n const eventName = binding.value\n const eventData = binding.arg ? { [binding.arg]: binding.modifiers } : {}\n tracker.track(eventName, eventData)\n }\n el.addEventListener('click', handler)\n cleanupMap.set(el, () => el.removeEventListener('click', handler))\n }),\n )\n\n // 曝光埋点指令\n appOrVue.directive(\n 'track-view',\n versionedDirective(v2, (el: HTMLElement, binding: any) => {\n if (typeof IntersectionObserver === 'undefined') {\n return\n }\n\n const observer = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n const eventName = binding.value\n tracker.track(`${eventName}_view`, {\n element: el.tagName,\n })\n // 只上报一次\n observer.unobserve(el)\n }\n })\n })\n\n observer.observe(el)\n cleanupMap.set(el, () => observer.disconnect())\n }),\n )\n\n // 停留时长埋点指令\n appOrVue.directive(\n 'track-stay',\n versionedDirective(v2, (el: HTMLElement, binding: any) => {\n if (typeof IntersectionObserver === 'undefined') {\n return\n }\n\n const startTime = Date.now()\n\n const observer = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if (!entry.isIntersecting) {\n const stayTime = Date.now() - startTime\n const eventName = binding.value\n\n tracker.track(`${eventName}_stay`, {\n stayTime,\n })\n }\n })\n })\n\n observer.observe(el)\n cleanupMap.set(el, () => observer.disconnect())\n }),\n )\n}\n\n/**\n * Vue Mixin\n */\nexport const GCTrackMixin = {\n methods: {\n /**\n * 追踪事件\n */\n $track(this: any, eventType: string, data?: Record<string, any>): void {\n if (this.$tracker) {\n this.$tracker.track(eventType, data)\n }\n },\n\n /**\n * 追踪页面浏览\n */\n $trackPageView(this: any, data?: Record<string, any>): void {\n if (this.$tracker) {\n this.$tracker.track('page_view', data)\n }\n },\n },\n}\n\n/**\n * 类型声明(Vue2 / Vue3 双端增强)\n */\n// @ts-ignore vue@3 无 vue/types/vue 子路径;此处增强对 Vue2 消费者侧仍生效,vue@3 构建时压制报错\ndeclare module 'vue/types/vue' {\n interface Vue {\n $tracker: Tracker\n $track: (eventType: string, data?: Record<string, any>) => void\n $trackPageView: (data?: Record<string, any>) => void\n }\n}\n\ndeclare module 'vue' {\n interface ComponentCustomProperties {\n $tracker: Tracker\n $track: (eventType: string, data?: Record<string, any>) => void\n $trackPageView: (data?: Record<string, any>) => void\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gctrack/vue",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Vue plugin for GCTrack",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -28,11 +28,19 @@
28
28
  "access": "public"
29
29
  },
30
30
  "peerDependencies": {
31
- "vue": "^2.6.0",
32
- "@gctrack/core": "0.1.2"
31
+ "vue": "^2.6.0 || ^3.0.0",
32
+ "@gctrack/core": "0.2.0"
33
+ },
34
+ "devDependencies": {
35
+ "@vue/test-utils": "^2.4.0",
36
+ "happy-dom": "^15.0.0",
37
+ "vue": "^3.4.0",
38
+ "vitest": "^2.0.0",
39
+ "@gctrack/core": "0.2.0"
33
40
  },
34
41
  "scripts": {
35
42
  "build": "tsdown",
36
- "dev": "tsdown --watch"
43
+ "dev": "tsdown --watch",
44
+ "test": "vitest run"
37
45
  }
38
46
  }