uview-pro 0.2.3 → 0.3.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.
Files changed (184) hide show
  1. package/changelog.md +52 -0
  2. package/components/u-action-sheet/types.ts +2 -0
  3. package/components/u-action-sheet/u-action-sheet.vue +25 -7
  4. package/components/u-alert-tips/types.ts +2 -0
  5. package/components/u-alert-tips/u-alert-tips.vue +36 -10
  6. package/components/u-avatar/types.ts +2 -0
  7. package/components/u-avatar/u-avatar.vue +31 -7
  8. package/components/u-avatar-cropper/u-avatar-cropper.vue +13 -2
  9. package/components/u-avatar-cropper/weCropper.js +36 -8
  10. package/components/u-avatar-cropper/weCropper.ts +28 -7
  11. package/components/u-back-top/types.ts +2 -5
  12. package/components/u-back-top/u-back-top.vue +31 -16
  13. package/components/u-badge/types.ts +2 -0
  14. package/components/u-badge/u-badge.vue +33 -15
  15. package/components/u-button/types.ts +2 -2
  16. package/components/u-button/u-button.vue +34 -11
  17. package/components/u-calendar/types.ts +3 -1
  18. package/components/u-calendar/u-calendar.vue +172 -17
  19. package/components/u-car-keyboard/types.ts +2 -0
  20. package/components/u-car-keyboard/u-car-keyboard.vue +36 -8
  21. package/components/u-card/types.ts +2 -0
  22. package/components/u-card/u-card.vue +25 -10
  23. package/components/u-cell-group/types.ts +2 -0
  24. package/components/u-cell-group/u-cell-group.vue +15 -5
  25. package/components/u-cell-item/types.ts +2 -0
  26. package/components/u-cell-item/u-cell-item.vue +37 -13
  27. package/components/u-checkbox/types.ts +2 -0
  28. package/components/u-checkbox/u-checkbox.vue +9 -13
  29. package/components/u-checkbox-group/types.ts +2 -0
  30. package/components/u-checkbox-group/u-checkbox-group.vue +1 -1
  31. package/components/u-circle-progress/types.ts +2 -0
  32. package/components/u-circle-progress/u-circle-progress.vue +30 -11
  33. package/components/u-city-select/types.ts +2 -0
  34. package/components/u-city-select/u-city-select.vue +48 -8
  35. package/components/u-col/types.ts +2 -0
  36. package/components/u-col/u-col.vue +27 -8
  37. package/components/u-collapse/u-collapse.vue +8 -13
  38. package/components/u-collapse-item/u-collapse-item.vue +21 -42
  39. package/components/u-column-notice/types.ts +2 -0
  40. package/components/u-column-notice/u-column-notice.vue +54 -8
  41. package/components/u-count-down/types.ts +2 -0
  42. package/components/u-count-down/u-count-down.vue +39 -11
  43. package/components/u-count-to/types.ts +2 -0
  44. package/components/u-count-to/u-count-to.vue +34 -9
  45. package/components/u-divider/types.ts +2 -0
  46. package/components/u-divider/u-divider.vue +36 -12
  47. package/components/u-dropdown/types.ts +2 -0
  48. package/components/u-dropdown/u-dropdown.vue +64 -23
  49. package/components/u-dropdown-item/types.ts +2 -0
  50. package/components/u-dropdown-item/u-dropdown-item.vue +39 -42
  51. package/components/u-empty/types.ts +2 -0
  52. package/components/u-empty/u-empty.vue +20 -5
  53. package/components/u-field/types.ts +2 -0
  54. package/components/u-field/u-field.vue +41 -7
  55. package/components/u-form/types.ts +2 -0
  56. package/components/u-form/u-form.vue +25 -27
  57. package/components/u-form-item/types.ts +2 -0
  58. package/components/u-form-item/u-form-item.vue +104 -74
  59. package/components/u-full-screen/types.ts +2 -0
  60. package/components/u-full-screen/u-full-screen.vue +24 -3
  61. package/components/u-gap/types.ts +2 -0
  62. package/components/u-gap/u-gap.vue +15 -5
  63. package/components/u-grid/types.ts +2 -0
  64. package/components/u-grid/u-grid.vue +23 -25
  65. package/components/u-grid-item/types.ts +3 -3
  66. package/components/u-grid-item/u-grid-item.vue +43 -43
  67. package/components/u-icon/types.ts +0 -1
  68. package/components/u-icon/u-icon.vue +20 -5
  69. package/components/u-image/u-image.vue +23 -6
  70. package/components/u-index-anchor/types.ts +3 -3
  71. package/components/u-index-anchor/u-index-anchor.vue +18 -10
  72. package/components/u-index-list/u-index-list.vue +9 -12
  73. package/components/u-input/types.ts +2 -5
  74. package/components/u-input/u-input.vue +34 -10
  75. package/components/u-keyboard/u-keyboard.vue +26 -6
  76. package/components/u-lazy-load/u-lazy-load.vue +23 -10
  77. package/components/u-line/u-line.vue +13 -4
  78. package/components/u-line-progress/u-line-progress.vue +22 -5
  79. package/components/u-link/u-link.vue +13 -4
  80. package/components/u-loading/u-loading.vue +20 -5
  81. package/components/u-loading-popup/u-loading-popup.vue +14 -0
  82. package/components/u-loadmore/u-loadmore.vue +19 -3
  83. package/components/u-mask/types.ts +2 -5
  84. package/components/u-mask/u-mask.vue +21 -14
  85. package/components/u-message-input/u-message-input.vue +32 -6
  86. package/components/u-modal/u-modal.vue +21 -5
  87. package/components/u-navbar/u-navbar.vue +31 -6
  88. package/components/u-no-network/u-no-network.vue +16 -3
  89. package/components/u-notice-bar/u-notice-bar.vue +19 -4
  90. package/components/u-number-box/u-number-box.vue +13 -4
  91. package/components/u-number-keyboard/u-number-keyboard.vue +32 -10
  92. package/components/u-picker/u-picker.vue +62 -14
  93. package/components/u-popup/types.ts +2 -2
  94. package/components/u-popup/u-popup.vue +33 -7
  95. package/components/u-radio/types.ts +2 -0
  96. package/components/u-radio/u-radio.vue +45 -24
  97. package/components/u-radio-group/types.ts +2 -0
  98. package/components/u-radio-group/u-radio-group.vue +20 -22
  99. package/components/u-rate/types.ts +2 -0
  100. package/components/u-rate/u-rate.vue +20 -5
  101. package/components/u-read-more/types.ts +2 -0
  102. package/components/u-read-more/u-read-more.vue +30 -8
  103. package/components/u-root-portal/u-root-portal.vue +3 -1
  104. package/components/u-row/types.ts +2 -0
  105. package/components/u-row/u-row.vue +29 -11
  106. package/components/u-row-notice/types.ts +2 -0
  107. package/components/u-row-notice/u-row-notice.vue +51 -8
  108. package/components/u-safe-bottom/u-safe-bottom.vue +13 -2
  109. package/components/u-search/types.ts +2 -0
  110. package/components/u-search/u-search.vue +30 -7
  111. package/components/u-section/types.ts +2 -0
  112. package/components/u-section/u-section.vue +38 -13
  113. package/components/u-select/types.ts +2 -0
  114. package/components/u-select/u-select.vue +37 -10
  115. package/components/u-skeleton/types.ts +2 -0
  116. package/components/u-skeleton/u-skeleton.vue +32 -6
  117. package/components/u-slider/types.ts +2 -0
  118. package/components/u-slider/u-slider.vue +38 -21
  119. package/components/u-status-bar/u-status-bar.vue +13 -4
  120. package/components/u-steps/types.ts +2 -0
  121. package/components/u-steps/u-steps.vue +26 -5
  122. package/components/u-sticky/types.ts +2 -0
  123. package/components/u-sticky/u-sticky.vue +27 -8
  124. package/components/u-subsection/types.ts +2 -0
  125. package/components/u-subsection/u-subsection.vue +14 -3
  126. package/components/u-swipe-action/types.ts +2 -0
  127. package/components/u-swipe-action/u-swipe-action.vue +27 -4
  128. package/components/u-swiper/types.ts +2 -0
  129. package/components/u-swiper/u-swiper.vue +50 -8
  130. package/components/u-switch/types.ts +2 -0
  131. package/components/u-switch/u-switch.vue +19 -5
  132. package/components/u-tabbar/types.ts +2 -0
  133. package/components/u-tabbar/u-tabbar.vue +42 -7
  134. package/components/u-table/types.ts +2 -0
  135. package/components/u-table/u-table.vue +15 -3
  136. package/components/u-tabs/types.ts +2 -0
  137. package/components/u-tabs/u-tabs.vue +22 -4
  138. package/components/u-tabs-swiper/types.ts +2 -0
  139. package/components/u-tabs-swiper/u-tabs-swiper.vue +36 -6
  140. package/components/u-tag/types.ts +2 -0
  141. package/components/u-tag/u-tag.vue +31 -7
  142. package/components/u-td/types.ts +2 -0
  143. package/components/u-td/u-td.vue +14 -3
  144. package/components/u-text/types.ts +4 -1
  145. package/components/u-text/u-text.vue +22 -5
  146. package/components/u-th/types.ts +2 -0
  147. package/components/u-th/u-th.vue +14 -3
  148. package/components/u-time-line/u-time-line.vue +17 -3
  149. package/components/u-time-line-item/types.ts +2 -0
  150. package/components/u-time-line-item/u-time-line-item.vue +15 -3
  151. package/components/u-toast/types.ts +2 -0
  152. package/components/u-toast/u-toast.vue +15 -8
  153. package/components/u-top-tips/types.ts +2 -0
  154. package/components/u-top-tips/u-top-tips.vue +20 -3
  155. package/components/u-tr/types.ts +4 -1
  156. package/components/u-tr/u-tr.vue +17 -2
  157. package/components/u-upload/types.ts +10 -2
  158. package/components/u-upload/u-upload.vue +31 -8
  159. package/components/u-verification-code/types.ts +2 -0
  160. package/components/u-verification-code/u-verification-code.vue +15 -3
  161. package/components/u-waterfall/types.ts +2 -0
  162. package/components/u-waterfall/u-waterfall.vue +15 -3
  163. package/iconfont.css +2 -1
  164. package/libs/css/style.vue.scss +1 -1
  165. package/libs/function/$parent.ts +4 -1
  166. package/libs/function/colorGradient.ts +18 -4
  167. package/libs/function/deepMerge.ts +2 -1
  168. package/libs/function/getParent.ts +5 -1
  169. package/libs/function/md5.ts +17 -5
  170. package/libs/function/queryParams.ts +5 -1
  171. package/libs/function/test.ts +7 -3
  172. package/libs/function/timeFormat.ts +2 -1
  173. package/libs/function/type2icon.ts +4 -1
  174. package/libs/hooks/index.ts +2 -1
  175. package/libs/hooks/useCompRelation.ts +364 -0
  176. package/libs/hooks/useComponent.ts +485 -69
  177. package/libs/hooks/useEmitter.ts +4 -2
  178. package/libs/index.ts +56 -39
  179. package/libs/request/index.ts +24 -5
  180. package/libs/util/async-validator.d.ts +16 -3
  181. package/libs/util/emitter.ts +12 -2
  182. package/libs/util/mitt.ts +4 -1
  183. package/package.json +1 -1
  184. package/readme.md +6 -6
@@ -1,11 +1,12 @@
1
1
  // utils/useComponent.ts
2
2
  import { ref, reactive, getCurrentInstance, onUnmounted, nextTick, computed } from 'vue';
3
3
  import { logger } from '../util/logger';
4
- import { eventBus } from '../util/eventBus';
4
+ import { mitt } from '../util/mitt';
5
5
 
6
6
  // 简化类型定义
7
7
  interface ParentContext {
8
8
  name: string;
9
+ uid: string; // 添加唯一ID
9
10
  addChild: (child: ChildContext) => void;
10
11
  removeChild: (childId: string) => void;
11
12
  broadcast: (event: string, data?: any) => void;
@@ -17,6 +18,7 @@ interface ParentContext {
17
18
 
18
19
  interface ChildContext {
19
20
  id: string;
21
+ uid: string; // 添加唯一ID
20
22
  name: string;
21
23
  emitToParent: (event: string, data?: any) => void;
22
24
  getParentExposed: () => Record<string, any>;
@@ -24,27 +26,129 @@ interface ChildContext {
24
26
  getExposed: () => Record<string, any>;
25
27
  }
26
28
 
27
- // 全局存储
28
- const parentMap = new Map<string, ParentContext>();
29
- const childMap = new Map<string, ChildContext>();
29
+ // 全局存储 - 改为页面级别存储
30
+ const pageComponentMaps = new Map<
31
+ string,
32
+ {
33
+ parentMap: Map<string, ParentContext>;
34
+ childMap: Map<string, ChildContext>;
35
+ }
36
+ >();
37
+
38
+ // 获取当前页面的组件映射
39
+ function getCurrentPageMaps() {
40
+ // 在uniapp中,可以通过getCurrentPages()获取当前页面路径
41
+ const pages = getCurrentPages();
42
+ const currentPage = pages[pages.length - 1];
43
+ const pagePath = currentPage?.route || 'default';
44
+
45
+ if (!pageComponentMaps.has(pagePath)) {
46
+ pageComponentMaps.set(pagePath, {
47
+ parentMap: new Map<string, ParentContext>(),
48
+ childMap: new Map<string, ChildContext>()
49
+ });
50
+ }
51
+
52
+ return pageComponentMaps.get(pagePath)!;
53
+ }
54
+
55
+ // 清理指定页面的组件关系
56
+ function cleanupPageComponentRelations(pagePath: string) {
57
+ if (pageComponentMaps.has(pagePath)) {
58
+ const pageMaps = pageComponentMaps.get(pagePath)!;
59
+ pageMaps.parentMap.clear();
60
+ pageMaps.childMap.clear();
61
+ pageComponentMaps.delete(pagePath);
62
+ logger.log(`Cleaned up component relations for page: ${pagePath}`);
63
+ }
64
+ }
30
65
 
31
66
  // 事件常量
32
67
  const PARENT_REGISTERED_EVENT = 'parent:registered';
33
68
  const PARENT_UNMOUNTED_EVENT = 'parent:unmounted';
34
69
  const CHILD_REGISTERED_EVENT = 'child:registered';
35
70
 
71
+ // 创建事件总线实例
72
+ type EventBusEvents = {
73
+ [PARENT_REGISTERED_EVENT]: { name: string; parent: ParentContext; pagePath: string };
74
+ [PARENT_UNMOUNTED_EVENT]: { name: string; pagePath: string };
75
+ [CHILD_REGISTERED_EVENT]: { id: string; name: string; parentName: string; pagePath: string };
76
+ [key: `parent:${string}:${string}`]: { data?: any; childId: string; childName: string; pagePath: string };
77
+ [key: `child:${string}:${string}`]: any;
78
+ };
79
+
80
+ const eventBus = mitt<EventBusEvents>();
81
+
82
+ // 热更新重新注册管理器
83
+ let isHotReloading = false;
84
+ const hotReloadReconnectCallbacks: Map<string, Function[]> = new Map();
85
+
86
+ /**
87
+ * 注册热更新重新连接回调
88
+ */
89
+ function registerHotReloadReconnect(key: string, callback: Function): void {
90
+ if (!hotReloadReconnectCallbacks.has(key)) {
91
+ hotReloadReconnectCallbacks.set(key, []);
92
+ }
93
+ hotReloadReconnectCallbacks.get(key)!.push(callback);
94
+ }
95
+
96
+ /**
97
+ * 注销热更新重新连接回调
98
+ */
99
+ function unregisterHotReloadReconnect(key: string, callback: Function): void {
100
+ const callbacks = hotReloadReconnectCallbacks.get(key);
101
+ if (callbacks) {
102
+ const index = callbacks.indexOf(callback);
103
+ if (index > -1) {
104
+ callbacks.splice(index, 1);
105
+ }
106
+ if (callbacks.length === 0) {
107
+ hotReloadReconnectCallbacks.delete(key);
108
+ }
109
+ }
110
+ }
111
+
112
+ /**
113
+ * 执行热更新重新连接
114
+ */
115
+ function executeHotReloadReconnect(): void {
116
+ logger.log('Executing hot reload reconnection for all registered callbacks');
117
+ hotReloadReconnectCallbacks.forEach((callbacks, key) => {
118
+ callbacks.forEach(callback => {
119
+ try {
120
+ callback();
121
+ logger.log(`Successfully reconnected: ${key}`);
122
+ } catch (error) {
123
+ logger.warn(`Failed to reconnect ${key}:`, error);
124
+ }
125
+ });
126
+ });
127
+ }
128
+
36
129
  // 热更新清理函数
37
130
  export function cleanupComponentRelations(): void {
38
131
  logger.log('Cleaning up component relations for hot reload');
39
- parentMap.clear();
40
- childMap.clear();
132
+ pageComponentMaps.clear();
133
+ eventBus.clear();
41
134
  }
42
135
 
43
136
  // 热更新处理
44
137
  if (import.meta.hot) {
45
138
  import.meta.hot.accept(() => {
139
+ isHotReloading = true;
140
+ logger.log('Hot reload detected, starting reconnection process');
141
+
142
+ // 第一步:清理旧的组件关系
46
143
  setTimeout(() => {
47
144
  cleanupComponentRelations();
145
+
146
+ // 第二步:执行重新连接
147
+ setTimeout(() => {
148
+ executeHotReloadReconnect();
149
+ isHotReloading = false;
150
+ logger.log('Hot reload reconnection completed');
151
+ }, 100); // 增加延迟确保组件已重新创建
48
152
  }, 50);
49
153
  });
50
154
  }
@@ -56,6 +160,27 @@ function generateInstanceId(componentName: string): string {
56
160
  return `${componentName}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
57
161
  }
58
162
 
163
+ /**
164
+ * 生成组件唯一UID
165
+ */
166
+ function generateComponentUid(): string {
167
+ return `uid_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
168
+ }
169
+
170
+ /**
171
+ * 获取当前页面路径
172
+ */
173
+ function getCurrentPagePath(): string {
174
+ // 在uniapp中获取当前页面路径
175
+ try {
176
+ const pages = getCurrentPages();
177
+ const currentPage = pages[pages.length - 1];
178
+ return currentPage?.route || 'default';
179
+ } catch (error) {
180
+ return 'default';
181
+ }
182
+ }
183
+
59
184
  /**
60
185
  * 父组件 Hook
61
186
  */
@@ -69,22 +194,32 @@ export function useParent(componentName: string) {
69
194
  throw new Error('Component name is required for useParent');
70
195
  }
71
196
 
197
+ const pagePath = getCurrentPagePath();
198
+ const pageMaps = getCurrentPageMaps();
199
+
200
+ // 生成父组件唯一UID
201
+ const parentUid = generateComponentUid();
202
+
203
+ // 使用组合名称:组件名 + UID,确保唯一性
204
+ const uniqueParentName = `${componentName}-${parentUid}`;
205
+
72
206
  // 热更新时清理旧的父组件
73
- if (parentMap.has(componentName)) {
74
- logger.log(`Cleaning up existing parent ${componentName} for hot reload`);
75
- parentMap.delete(componentName);
207
+ if (pageMaps.parentMap.has(uniqueParentName)) {
208
+ logger.log(`Cleaning up existing parent ${uniqueParentName} for hot reload on page ${pagePath}`);
209
+ pageMaps.parentMap.delete(uniqueParentName);
76
210
  }
77
211
 
78
212
  const children = reactive<ChildContext[]>([]);
79
213
 
80
214
  // 父组件上下文
81
215
  const parentContext: ParentContext = {
82
- name: componentName,
216
+ name: uniqueParentName, // 使用唯一名称
217
+ uid: parentUid, // 添加唯一ID
83
218
 
84
219
  addChild(child: ChildContext) {
85
220
  if (!children.find(c => c.id === child.id)) {
86
221
  children.push(child);
87
- logger.log(`Parent ${componentName} added child: ${child.name}`);
222
+ logger.log(`Parent ${uniqueParentName} on page ${pagePath} added child: ${child.name}`);
88
223
  }
89
224
  },
90
225
 
@@ -92,12 +227,12 @@ export function useParent(componentName: string) {
92
227
  const index = children.findIndex(c => c.id === childId);
93
228
  if (index > -1) {
94
229
  children.splice(index, 1);
95
- logger.log(`Parent ${componentName} removed child: ${childId}`);
230
+ logger.log(`Parent ${uniqueParentName} on page ${pagePath} removed child: ${childId}`);
96
231
  }
97
232
  },
98
233
 
99
234
  broadcast(event: string, data?: any) {
100
- logger.log(`Parent ${componentName} broadcasting event: ${event}`);
235
+ logger.log(`Parent ${uniqueParentName} on page ${pagePath} broadcasting event: ${event}`);
101
236
  children.forEach(child => {
102
237
  eventBus.emit(`child:${child.id}:${event}`, data);
103
238
  });
@@ -116,7 +251,7 @@ export function useParent(componentName: string) {
116
251
  if (child && child.getExposed) {
117
252
  return child.getExposed();
118
253
  }
119
- logger.warn(`Child ${childId} not found or does not have getExposed method`);
254
+ logger.warn(`Child ${childId} not found or does not have getExposed method on page ${pagePath}`);
120
255
  return {};
121
256
  },
122
257
 
@@ -136,26 +271,35 @@ export function useParent(componentName: string) {
136
271
  };
137
272
 
138
273
  // 注册父组件并广播事件
139
- parentMap.set(componentName, parentContext);
140
- logger.log(`Parent ${componentName} registered`);
141
-
142
- // 广播父组件注册事件
143
- eventBus.emit(PARENT_REGISTERED_EVENT, { name: componentName, parent: parentContext });
274
+ pageMaps.parentMap.set(uniqueParentName, parentContext);
275
+ logger.log(`Parent ${uniqueParentName} registered on page ${pagePath}`);
276
+
277
+ // 广播父组件注册事件(包含页面路径信息)
278
+ eventBus.emit(PARENT_REGISTERED_EVENT, {
279
+ name: uniqueParentName,
280
+ parent: parentContext,
281
+ pagePath
282
+ });
144
283
 
145
284
  // 组件卸载时清理
146
285
  onUnmounted(() => {
147
- parentMap.delete(componentName);
148
- eventBus.emit(PARENT_UNMOUNTED_EVENT, { name: componentName });
149
- logger.log(`Parent ${componentName} unmounted`);
286
+ pageMaps.parentMap.delete(uniqueParentName);
287
+ eventBus.emit(PARENT_UNMOUNTED_EVENT, {
288
+ name: uniqueParentName,
289
+ pagePath
290
+ });
291
+ logger.log(`Parent ${uniqueParentName} unmounted from page ${pagePath}`);
150
292
  });
151
293
 
152
294
  return {
153
- parentName: componentName,
295
+ parentName: uniqueParentName, // 返回唯一名称
296
+ parentUid, // 返回唯一ID
154
297
  children,
155
298
  broadcast: parentContext.broadcast,
156
299
  getChildren: parentContext.getChildren,
157
300
  getChildExposed: parentContext.getChildExposed,
158
- getChildrenExposed: parentContext.getChildrenExposed
301
+ getChildrenExposed: parentContext.getChildrenExposed,
302
+ pagePath
159
303
  };
160
304
  }
161
305
 
@@ -172,14 +316,17 @@ export function useChildren(componentName: string, parentName: string) {
172
316
  throw new Error('Component name and parent name are required for useChildren');
173
317
  }
174
318
 
319
+ const pagePath = getCurrentPagePath();
320
+ const pageMaps = getCurrentPageMaps();
175
321
  const instanceId = generateInstanceId(componentName);
322
+ const childUid = generateComponentUid(); // 生成子组件唯一UID
176
323
  const parentRef = ref<ParentContext | null>(null);
177
324
  const parentExposed = ref<Record<string, any>>({});
178
325
 
179
326
  // 热更新时清理旧的子组件
180
- if (childMap.has(instanceId)) {
181
- logger.log(`Cleaning up existing child ${componentName} for hot reload`);
182
- childMap.delete(instanceId);
327
+ if (pageMaps.childMap.has(instanceId)) {
328
+ logger.log(`Cleaning up existing child ${componentName} for hot reload on page ${pagePath}`);
329
+ pageMaps.childMap.delete(instanceId);
183
330
  }
184
331
 
185
332
  // 获取父组件暴露内容
@@ -197,14 +344,29 @@ export function useChildren(componentName: string, parentName: string) {
197
344
  return instance.exposed || {};
198
345
  };
199
346
 
200
- // 链接到父组件
347
+ // 链接到父组件(只在当前页面查找)
201
348
  const linkParent = (): boolean => {
202
- const parent = parentMap.get(parentName);
349
+ // 在当前页面中查找匹配的父组件
350
+ let parent: ParentContext | undefined;
351
+
352
+ // 首先尝试精确匹配
353
+ parent = pageMaps.parentMap.get(parentName);
354
+
355
+ // 如果精确匹配失败,尝试前缀匹配(支持向后兼容)
356
+ if (!parent) {
357
+ for (const [key, value] of pageMaps.parentMap.entries()) {
358
+ if (key.startsWith(parentName + '-')) {
359
+ parent = value;
360
+ break;
361
+ }
362
+ }
363
+ }
364
+
203
365
  if (parent) {
204
366
  parentRef.value = parent;
205
367
  parent.addChild(childContext);
206
368
  getParentExposed();
207
- logger.log(`Child ${componentName} linked to parent ${parentName}`);
369
+ logger.log(`Child ${componentName} linked to parent ${parent.name} on page ${pagePath}`);
208
370
  return true;
209
371
  }
210
372
  return false;
@@ -213,14 +375,18 @@ export function useChildren(componentName: string, parentName: string) {
213
375
  // 子组件上下文
214
376
  const childContext: ChildContext = {
215
377
  id: instanceId,
378
+ uid: childUid, // 添加唯一ID
216
379
  name: componentName,
217
380
 
218
381
  emitToParent(event: string, data?: any) {
219
- eventBus.emit(`parent:${parentName}:${event}`, {
220
- data,
221
- childId: instanceId,
222
- childName: componentName
223
- });
382
+ if (parentRef.value) {
383
+ eventBus.emit(`parent:${parentRef.value.name}:${event}`, {
384
+ data,
385
+ childId: instanceId,
386
+ childName: componentName,
387
+ pagePath
388
+ });
389
+ }
224
390
  },
225
391
 
226
392
  getParentExposed,
@@ -231,23 +397,28 @@ export function useChildren(componentName: string, parentName: string) {
231
397
  };
232
398
 
233
399
  // 注册子组件
234
- childMap.set(instanceId, childContext);
235
- logger.log(`Child ${componentName} registered`);
400
+ pageMaps.childMap.set(instanceId, childContext);
401
+ logger.log(`Child ${componentName} registered on page ${pagePath}`);
236
402
 
237
403
  // 广播子组件注册事件
238
404
  eventBus.emit(CHILD_REGISTERED_EVENT, {
239
405
  id: instanceId,
240
406
  name: componentName,
241
- parentName: parentName
407
+ parentName: parentName,
408
+ pagePath
242
409
  });
243
410
 
244
411
  // 立即尝试连接父组件
245
412
  let connected = linkParent();
246
413
 
247
- // 如果没连接上,监听父组件注册事件
414
+ // 如果没连接上,监听父组件注册事件(只监听当前页面的父组件)
248
415
  if (!connected) {
249
- const parentRegisteredHandler = (eventData: any) => {
250
- if (eventData.name === parentName) {
416
+ const parentRegisteredHandler = (eventData: { name: string; parent: ParentContext; pagePath: string }) => {
417
+ // 检查是否是我们要连接的父组件(精确匹配或前缀匹配)
418
+ if (
419
+ (eventData.name === parentName || eventData.name.startsWith(parentName + '-')) &&
420
+ eventData.pagePath === pagePath
421
+ ) {
251
422
  connected = linkParent();
252
423
  if (connected) {
253
424
  eventBus.off(PARENT_REGISTERED_EVENT, parentRegisteredHandler);
@@ -257,12 +428,16 @@ export function useChildren(componentName: string, parentName: string) {
257
428
  eventBus.on(PARENT_REGISTERED_EVENT, parentRegisteredHandler);
258
429
  }
259
430
 
260
- // 监听父组件卸载事件
261
- const parentUnmountedHandler = (eventData: any) => {
262
- if (eventData.name === parentName && parentRef.value) {
431
+ // 监听父组件卸载事件(只监听当前页面的父组件)
432
+ const parentUnmountedHandler = (eventData: { name: string; pagePath: string }) => {
433
+ if (
434
+ (eventData.name === parentName || eventData.name.startsWith(parentName + '-')) &&
435
+ eventData.pagePath === pagePath &&
436
+ parentRef.value
437
+ ) {
263
438
  parentRef.value = null;
264
439
  parentExposed.value = {};
265
- logger.log(`Parent ${parentName} unmounted, child ${componentName} disconnected`);
440
+ logger.log(`Parent ${parentName} unmounted from page ${pagePath}, child ${componentName} disconnected`);
266
441
  }
267
442
  };
268
443
  eventBus.on(PARENT_UNMOUNTED_EVENT, parentUnmountedHandler);
@@ -272,72 +447,313 @@ export function useChildren(componentName: string, parentName: string) {
272
447
  if (parentRef.value) {
273
448
  parentRef.value.removeChild(instanceId);
274
449
  }
275
- childMap.delete(instanceId);
450
+ pageMaps.childMap.delete(instanceId);
276
451
  eventBus.off(PARENT_REGISTERED_EVENT);
277
452
  eventBus.off(PARENT_UNMOUNTED_EVENT, parentUnmountedHandler);
278
- logger.log(`Child ${componentName} unmounted`);
453
+ logger.log(`Child ${componentName} unmounted from page ${pagePath}`);
279
454
  });
280
455
 
281
456
  return {
282
457
  childId: instanceId,
458
+ childUid, // 返回唯一ID
283
459
  childName: componentName,
284
460
  parent: parentRef,
285
461
  emitToParent: childContext.emitToParent,
286
462
  getParentExposed,
287
463
  parentExposed: computed(() => parentExposed.value),
288
- getExposed: childContext.getExposed
464
+ getExposed: childContext.getExposed,
465
+ pagePath
289
466
  };
290
467
  }
291
468
 
292
469
  /**
293
- * 监听子组件事件
470
+ * 监听子组件事件(返回取消监听函数)
294
471
  */
295
- export function onChildEvent(parentName: string, event: string, handler: Function) {
296
- eventBus.on(`parent:${parentName}:${event}`, eventData => {
297
- handler(eventData.data, eventData.childId, eventData.childName);
298
- });
472
+ export function onChildEvent(
473
+ parentName: string,
474
+ event: string,
475
+ handler: (data?: any, childId?: string, childName?: string) => void
476
+ ): () => void {
477
+ const pagePath = getCurrentPagePath();
478
+
479
+ const eventHandler = (eventData: { data?: any; childId: string; childName: string; pagePath: string }) => {
480
+ // 只处理当前页面的事件
481
+ if (eventData.pagePath === pagePath) {
482
+ handler(eventData.data, eventData.childId, eventData.childName);
483
+ }
484
+ };
485
+
486
+ eventBus.on(`parent:${parentName}:${event}`, eventHandler);
487
+
488
+ // 返回取消监听函数
489
+ return () => {
490
+ eventBus.off(`parent:${parentName}:${event}`, eventHandler);
491
+ };
299
492
  }
300
493
 
301
494
  /**
302
- * 监听父组件事件
495
+ * 监听父组件事件(返回取消监听函数)
303
496
  */
304
- export function onParentEvent(childId: string, event: string, handler: Function) {
305
- // 修复类型问题:将 Function 转换为 EventCallback
306
- const eventCallback = (data?: any, ...args: any[]) => {
307
- handler(data, ...args);
308
- };
309
- eventBus.on(`child:${childId}:${event}`, eventCallback);
497
+ export function onParentEvent(childId: string, event: string, handler: (data?: any) => void): () => void {
498
+ eventBus.on(`child:${childId}:${event}`, handler);
310
499
 
311
500
  // 返回取消监听函数
312
501
  return () => {
313
- eventBus.off(`child:${childId}:${event}`, eventCallback);
502
+ eventBus.off(`child:${childId}:${event}`, handler);
314
503
  };
315
504
  }
316
505
 
317
506
  /**
318
- * 检查父组件是否存在
507
+ * 自动取消监听的事件注册 - 单个事件
508
+ */
509
+ export function useParentEvent(
510
+ childId: string,
511
+ event: string,
512
+ handler: (data?: any) => void,
513
+ autoClean = true,
514
+ hotReloadReconnect = true
515
+ ): () => void {
516
+ const instance = getCurrentInstance();
517
+ const unsubscribe = onParentEvent(childId, event, handler);
518
+
519
+ // 热更新重新注册支持
520
+ if (hotReloadReconnect && instance) {
521
+ const reconnectKey = `parent-event-${childId}-${event}`;
522
+ const reconnectCallback = () => {
523
+ logger.log(`Reconnecting parent event: ${event} for child: ${childId}`);
524
+ onParentEvent(childId, event, handler);
525
+ };
526
+
527
+ registerHotReloadReconnect(reconnectKey, reconnectCallback);
528
+
529
+ // 组件卸载时清理重新注册回调
530
+ onUnmounted(() => {
531
+ unregisterHotReloadReconnect(reconnectKey, reconnectCallback);
532
+ });
533
+ }
534
+
535
+ // 自动在组件卸载时清理
536
+ if (autoClean && instance) {
537
+ onUnmounted(unsubscribe);
538
+ }
539
+
540
+ return unsubscribe;
541
+ }
542
+
543
+ /**
544
+ * 自动取消监听的事件注册 - 批量事件
545
+ */
546
+ export function useParentEvents(
547
+ childId: string,
548
+ events: Record<string, (data?: any) => void>,
549
+ autoClean = true,
550
+ hotReloadReconnect = true
551
+ ): () => void {
552
+ const instance = getCurrentInstance();
553
+ const cleanups: Function[] = [];
554
+
555
+ Object.entries(events).forEach(([event, handler]) => {
556
+ const unsubscribe = onParentEvent(childId, event, handler);
557
+ cleanups.push(unsubscribe);
558
+
559
+ // 热更新重新注册支持
560
+ if (hotReloadReconnect && instance) {
561
+ const reconnectKey = `parent-events-${childId}-${event}`;
562
+ const reconnectCallback = () => {
563
+ logger.log(`Reconnecting parent event: ${event} for child: ${childId}`);
564
+ onParentEvent(childId, event, handler);
565
+ };
566
+
567
+ registerHotReloadReconnect(reconnectKey, reconnectCallback);
568
+
569
+ // 组件卸载时清理重新注册回调
570
+ onUnmounted(() => {
571
+ unregisterHotReloadReconnect(reconnectKey, reconnectCallback);
572
+ });
573
+ }
574
+ });
575
+
576
+ const cleanupAll = () => {
577
+ cleanups.forEach(cleanup => cleanup());
578
+ cleanups.length = 0;
579
+ };
580
+
581
+ if (autoClean && instance) {
582
+ onUnmounted(cleanupAll);
583
+ }
584
+
585
+ return cleanupAll;
586
+ }
587
+
588
+ /**
589
+ * 自动取消监听的子组件事件注册 - 单个事件
590
+ */
591
+ export function useChildEvent(
592
+ parentName: string,
593
+ event: string,
594
+ handler: (data?: any, childId?: string, childName?: string) => void,
595
+ autoClean = true,
596
+ hotReloadReconnect = true
597
+ ): () => void {
598
+ const instance = getCurrentInstance();
599
+ const unsubscribe = onChildEvent(parentName, event, handler);
600
+
601
+ // 热更新重新注册支持
602
+ if (hotReloadReconnect && instance) {
603
+ const reconnectKey = `child-event-${parentName}-${event}`;
604
+ const reconnectCallback = () => {
605
+ logger.log(`Reconnecting child event: ${event} for parent: ${parentName}`);
606
+ onChildEvent(parentName, event, handler);
607
+ };
608
+
609
+ registerHotReloadReconnect(reconnectKey, reconnectCallback);
610
+
611
+ // 组件卸载时清理重新注册回调
612
+ onUnmounted(() => {
613
+ unregisterHotReloadReconnect(reconnectKey, reconnectCallback);
614
+ });
615
+ }
616
+
617
+ // 自动在组件卸载时清理
618
+ if (autoClean && instance) {
619
+ onUnmounted(unsubscribe);
620
+ }
621
+
622
+ return unsubscribe;
623
+ }
624
+
625
+ /**
626
+ * 自动取消监听的子组件事件注册 - 批量事件
627
+ */
628
+ export function useChildEvents(
629
+ parentName: string,
630
+ events: Record<string, (data?: any, childId?: string, childName?: string) => void>,
631
+ autoClean = true,
632
+ hotReloadReconnect = true
633
+ ): () => void {
634
+ const instance = getCurrentInstance();
635
+ const cleanups: Function[] = [];
636
+
637
+ Object.entries(events).forEach(([event, handler]) => {
638
+ const unsubscribe = onChildEvent(parentName, event, handler);
639
+ cleanups.push(unsubscribe);
640
+
641
+ // 热更新重新注册支持
642
+ if (hotReloadReconnect && instance) {
643
+ const reconnectKey = `child-events-${parentName}-${event}`;
644
+ const reconnectCallback = () => {
645
+ logger.log(`Reconnecting child event: ${event} for parent: ${parentName}`);
646
+ onChildEvent(parentName, event, handler);
647
+ };
648
+
649
+ registerHotReloadReconnect(reconnectKey, reconnectCallback);
650
+
651
+ // 组件卸载时清理重新注册回调
652
+ onUnmounted(() => {
653
+ unregisterHotReloadReconnect(reconnectKey, reconnectCallback);
654
+ });
655
+ }
656
+ });
657
+
658
+ const cleanupAll = () => {
659
+ cleanups.forEach(cleanup => cleanup());
660
+ cleanups.length = 0;
661
+ };
662
+
663
+ if (autoClean && instance) {
664
+ onUnmounted(cleanupAll);
665
+ }
666
+
667
+ return cleanupAll;
668
+ }
669
+
670
+ /**
671
+ * 检查父组件是否存在(在当前页面)
319
672
  */
320
673
  export function hasParent(parentName: string): boolean {
321
- return parentMap.has(parentName);
674
+ const pageMaps = getCurrentPageMaps();
675
+
676
+ // 精确匹配
677
+ if (pageMaps.parentMap.has(parentName)) {
678
+ return true;
679
+ }
680
+
681
+ // 前缀匹配(支持向后兼容)
682
+ for (const key of pageMaps.parentMap.keys()) {
683
+ if (key.startsWith(parentName + '-')) {
684
+ return true;
685
+ }
686
+ }
687
+
688
+ return false;
322
689
  }
323
690
 
324
691
  /**
325
- * 获取所有已注册的父组件名称
692
+ * 获取所有已注册的父组件名称(当前页面)
326
693
  */
327
694
  export function getRegisteredParents(): string[] {
328
- return Array.from(parentMap.keys());
695
+ const pageMaps = getCurrentPageMaps();
696
+ return Array.from(pageMaps.parentMap.keys());
329
697
  }
330
698
 
331
699
  /**
332
- * 获取父组件实例
700
+ * 获取父组件实例(当前页面)
333
701
  */
334
702
  export function getParent(parentName: string): ParentContext | undefined {
335
- return parentMap.get(parentName);
703
+ const pageMaps = getCurrentPageMaps();
704
+
705
+ // 精确匹配
706
+ let parent = pageMaps.parentMap.get(parentName);
707
+ if (parent) {
708
+ return parent;
709
+ }
710
+
711
+ // 前缀匹配(支持向后兼容)
712
+ for (const [key, value] of pageMaps.parentMap.entries()) {
713
+ if (key.startsWith(parentName + '-')) {
714
+ return value;
715
+ }
716
+ }
717
+
718
+ return undefined;
336
719
  }
337
720
 
338
721
  /**
339
- * 获取子组件实例
722
+ * 获取子组件实例(当前页面)
340
723
  */
341
724
  export function getChild(childId: string): ChildContext | undefined {
342
- return childMap.get(childId);
725
+ const pageMaps = getCurrentPageMaps();
726
+ return pageMaps.childMap.get(childId);
727
+ }
728
+
729
+ /**
730
+ * 清理当前页面的组件关系(用于页面卸载时调用)
731
+ */
732
+ export function cleanupCurrentPageComponents(): void {
733
+ const pagePath = getCurrentPagePath();
734
+ cleanupPageComponentRelations(pagePath);
735
+ logger.log(`Cleaned up component relations for current page: ${pagePath}`);
736
+ }
737
+
738
+ /**
739
+ * 手动触发热更新重新连接(用于调试)
740
+ */
741
+ export function manualHotReloadReconnect(): void {
742
+ logger.log('Manual hot reload reconnection triggered');
743
+ executeHotReloadReconnect();
744
+ }
745
+
746
+ /**
747
+ * 获取热更新状态
748
+ */
749
+ export function getHotReloadStatus(): { isHotReloading: boolean; reconnectCallbacksCount: number } {
750
+ let totalCallbacks = 0;
751
+ hotReloadReconnectCallbacks.forEach(callbacks => {
752
+ totalCallbacks += callbacks.length;
753
+ });
754
+
755
+ return {
756
+ isHotReloading,
757
+ reconnectCallbacksCount: totalCallbacks
758
+ };
343
759
  }