uview-pro 0.3.2 → 0.3.3

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/changelog.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## 0.3.3(2025-10-16)
2
+
3
+ ### 🐛 Bug Fixes | Bug 修复
4
+
5
+ - **u-read-more:** 修复 init 方法无法在外部调用的问题 ([415d401](https://github.com/anyup/uView-Pro/commit/415d401883a3567653ab1f311b28b075b7bb5603))
6
+ - **u-button:** 修复 hover-class 属性被忽略的问题 ([b919c58](https://github.com/anyup/uView-Pro/commit/b919c58cea048f9e559a6448cebe5abbf1490acf))
7
+
8
+ ### ♻️ Code Refactoring | 代码重构
9
+
10
+ - **component-relation:** 重构组件关系逻辑并添加新功能 ([85d0cd2](https://github.com/anyup/uView-Pro/commit/85d0cd20db839a61733887f82825d47de0a1b1a6))
11
+ - **u-talbe:** 重构u-td和u-th组件,增强u-table的兼容性 ([3fbbc52](https://github.com/anyup/uView-Pro/commit/3fbbc5233bd41b91ca829f9a65cf95ee3b599e36))
12
+ - 修改 uView Pro 日志配置 ([6b9bb68](https://github.com/anyup/uView-Pro/commit/6b9bb6852af3eb24f109207f864145771c3e9c79))
13
+ - **clipboard:** add clipboard function ([efdaa58](https://github.com/anyup/uView-Pro/commit/efdaa58dda923b281d9b764a82a7492f36717ac4))
14
+
15
+ ### 👥 Contributors
16
+
17
+ <a href="https://github.com/koboshi"><img src="https://github.com/koboshi.png?size=40" width="40" height="40" alt="koboshi" title="koboshi"/></a> <a href="https://github.com/anyup"><img src="https://github.com/anyup.png?size=40" width="40" height="40" alt="anyup" title="anyup"/></a> <a href="https://github.com/lonelyflyer"><img src="https://github.com/lonelyflyer.png?size=40" width="40" height="40" alt="Lonelyflyer" title="Lonelyflyer"/></a>
18
+
1
19
  ## 0.3.2(2025-10-15)
2
20
 
3
21
  ### 📝 Documentation | 文档
@@ -151,7 +151,9 @@ const waveActive = ref(false); // 激活水波纹
151
151
  */
152
152
  const getHoverClass = computed(() => {
153
153
  // 如果开启水波纹效果,则不启用hover-class效果
154
- if (props.loading || props.disabled || props.ripple || props.hoverClass) return '';
154
+ if (props.loading || props.disabled || props.ripple) return '';
155
+ // 如果用户传了 hoverClass,优先使用用户的
156
+ if (props.hoverClass) return props.hoverClass;
155
157
  let hoverClass = '';
156
158
  hoverClass = props.plain ? 'u-' + props.type + '-plain-hover' : 'u-' + props.type + '-hover';
157
159
  return hoverClass;
@@ -119,6 +119,10 @@ function init() {
119
119
  }
120
120
  });
121
121
  }
122
+ // 显式暴露init方法
123
+ defineExpose({
124
+ init
125
+ });
122
126
 
123
127
  /**
124
128
  * 展开或者收起内容
@@ -18,8 +18,8 @@ export default {
18
18
  </script>
19
19
 
20
20
  <script setup lang="ts">
21
- import { ref, onMounted, getCurrentInstance, watch } from 'vue';
22
- import { $u } from '../..';
21
+ import { computed } from 'vue';
22
+ import { $u, useChildren } from '../..';
23
23
  import { TdProps } from './types';
24
24
 
25
25
  /**
@@ -32,52 +32,19 @@ import { TdProps } from './types';
32
32
 
33
33
  const props = defineProps(TdProps);
34
34
 
35
- /**
36
- * 组合式API变量声明
37
- * 保留所有说明注释
38
- */
39
- const tdStyle = ref<Record<string, any>>({}); // 单元格样式
40
- let parent: any = null; // 父组件实例
41
-
42
- /**
43
- * 更新单元格样式
44
- */
45
- function updateStyle() {
46
- if (!parent) return;
35
+ const { parentExposed } = useChildren('u-td', 'u-table');
47
36
 
37
+ const tdStyle = computed(() => {
48
38
  const style: Record<string, any> = {};
49
39
  if (props.width && props.width !== 'auto') style.width = props.width;
50
40
  else style.flex = '1';
51
- style.textAlign = parent.props.align;
52
- style.fontSize = parent.props.fontSize + 'rpx';
53
- style.padding = parent.props.padding;
54
- style.borderBottom = `solid 1px ${parent.props.borderColor}`;
55
- style.borderRight = `solid 1px ${parent.props.borderColor}`;
56
- style.color = parent.props.color;
57
- tdStyle.value = style;
58
- }
59
-
60
- /**
61
- * 组件挂载时查找父组件u-table并合并样式
62
- */
63
- onMounted(() => {
64
- // 查找父组件u-table
65
- const instance = getCurrentInstance();
66
- if (instance) {
67
- parent = $u.$parent('u-table');
68
- if (parent) {
69
- updateStyle();
70
-
71
- // 监听父组件属性变化
72
- watch(
73
- () => parent.props,
74
- () => {
75
- updateStyle();
76
- },
77
- { deep: true }
78
- );
79
- }
80
- }
41
+ style.textAlign = parentExposed.value?.props?.align;
42
+ style.fontSize = parentExposed.value?.props?.fontSize + 'rpx';
43
+ style.padding = parentExposed.value?.props?.padding;
44
+ style.borderBottom = `solid 1px ${parentExposed.value?.props?.borderColor}`;
45
+ style.borderRight = `solid 1px ${parentExposed.value?.props?.borderColor}`;
46
+ style.color = parentExposed.value?.props?.color;
47
+ return style;
81
48
  });
82
49
  </script>
83
50
 
@@ -18,8 +18,8 @@ export default {
18
18
  </script>
19
19
 
20
20
  <script setup lang="ts">
21
- import { ref, onMounted, getCurrentInstance, watch } from 'vue';
22
- import { $u } from '../..';
21
+ import { computed } from 'vue';
22
+ import { $u, useChildren } from '../..';
23
23
  import { ThProps } from './types';
24
24
 
25
25
  /**
@@ -32,47 +32,18 @@ import { ThProps } from './types';
32
32
 
33
33
  const props = defineProps(ThProps);
34
34
 
35
- const thStyle = ref<Record<string, any>>({}); // 标题单元格样式
36
- let parent: any = null; // 父组件实例
37
-
38
- /**
39
- * 更新标题单元格样式
40
- */
41
- function updateStyle() {
42
- if (!parent) return;
35
+ const { parentExposed } = useChildren('u-th', 'u-table');
43
36
 
37
+ const thStyle = computed(() => {
44
38
  const style: Record<string, any> = {};
45
39
  if (props.width && props.width !== 'auto') style.width = props.width;
46
40
  else style.flex = '1';
47
- style.textAlign = parent.props.align;
48
- style.padding = parent.props.padding;
49
- style.borderBottom = `solid 1px ${parent.props.borderColor}`;
50
- style.borderRight = `solid 1px ${parent.props.borderColor}`;
51
- Object.assign(style, parent.props.thStyle);
52
- thStyle.value = style;
53
- }
54
-
55
- /**
56
- * 组件挂载时查找父组件u-table并合并样式
57
- */
58
- onMounted(() => {
59
- // 查找父组件u-table
60
- const instance = getCurrentInstance();
61
- if (instance) {
62
- parent = $u.$parent('u-table');
63
- if (parent) {
64
- updateStyle();
65
-
66
- // 监听父组件属性变化
67
- watch(
68
- () => parent.props,
69
- () => {
70
- updateStyle();
71
- },
72
- { deep: true }
73
- );
74
- }
75
- }
41
+ style.textAlign = parentExposed.value?.props?.align;
42
+ style.padding = parentExposed.value?.props?.padding;
43
+ style.borderBottom = `solid 1px ${parentExposed.value?.props?.borderColor}`;
44
+ style.borderRight = `solid 1px ${parentExposed.value?.props?.borderColor}`;
45
+ Object.assign(style, parentExposed.value?.props?.thStyle);
46
+ return style;
76
47
  });
77
48
  </script>
78
49
 
@@ -0,0 +1,78 @@
1
+ function H5Copy(text: string, config: TClipboardOptions) {
2
+ const success = (result: string) => {
3
+ if (config.showToast) {
4
+ uni.showToast({
5
+ title: '复制成功',
6
+ icon: 'none'
7
+ });
8
+ }
9
+ config.success(result);
10
+ config.complete(result);
11
+ };
12
+ const fail = (err: string) => {
13
+ if (config.showToast) {
14
+ uni.showToast({
15
+ title: '复制失败',
16
+ icon: 'none'
17
+ });
18
+ }
19
+ config.fail(err);
20
+ config.complete(err);
21
+ };
22
+
23
+ const textarea = document.createElement('textarea');
24
+ textarea.value = text;
25
+ textarea.readOnly = true;
26
+ textarea.style.position = 'absolute';
27
+ textarea.style.left = '-9999px';
28
+ document.body.appendChild(textarea);
29
+
30
+ textarea.select();
31
+ textarea.setSelectionRange(0, text.length);
32
+
33
+ try {
34
+ const result = document.execCommand('copy');
35
+ if (result) {
36
+ success('复制成功');
37
+ } else {
38
+ // console.error(`复制失败,可能不是用户主动触发点击的方式调用,因web安全性,不能js直接调用!`);
39
+ fail('复制失败,可能不是用户主动触发点击的方式调用,因browser安全性,不能js直接调用!');
40
+ }
41
+ } catch (err) {
42
+ // console.error('【Clipboard Error】:', err);
43
+ fail(err);
44
+ } finally {
45
+ document.body.removeChild(textarea);
46
+ }
47
+ }
48
+
49
+ function UniCopy(text: string, config: TClipboardOptions) {
50
+ const opt = Object.assign({ data: text }, config);
51
+ console.log(opt);
52
+ uni.setClipboardData(opt);
53
+ }
54
+
55
+ type TClipboardOptions = Omit<UniNamespace.SetClipboardDataOptions, 'data'>;
56
+
57
+ export function clipboard(content: string, options?: TClipboardOptions) {
58
+ const text = String(content);
59
+ const showToast = typeof options.showToast === 'boolean' ? options.showToast : true;
60
+ const copySuccessCb = typeof options.success === 'function' ? options.success : () => {};
61
+ const copyFailCb = typeof options.success === 'function' ? options.fail : () => {};
62
+ const copyCompleteCb = typeof options.complete === 'function' ? options.complete : () => {};
63
+
64
+ let config: TClipboardOptions = {
65
+ showToast,
66
+ success: copySuccessCb,
67
+ fail: copyFailCb,
68
+ complete: copyCompleteCb
69
+ };
70
+
71
+ // #ifdef H5
72
+ H5Copy(text, config);
73
+ // #endif
74
+
75
+ // #ifndef H5
76
+ UniCopy(text, config);
77
+ // #endif
78
+ }
@@ -1,5 +1,14 @@
1
1
  // utils/useComponent.ts
2
- import { ref, reactive, getCurrentInstance, onUnmounted, nextTick, computed, watch, onMounted } from 'vue';
2
+ import {
3
+ ref,
4
+ reactive,
5
+ getCurrentInstance,
6
+ onUnmounted,
7
+ nextTick,
8
+ computed,
9
+ onMounted,
10
+ type ComponentInternalInstance
11
+ } from 'vue';
3
12
  import { logger } from '../util/logger';
4
13
 
5
14
  // 类型定义
@@ -7,11 +16,13 @@ interface ParentContext {
7
16
  name: string;
8
17
  addChild: (child: ChildContext) => void;
9
18
  removeChild: (childId: string) => void;
10
- broadcast: (event: string, data?: any, childIds?: string | string[]) => void; // 修改:支持定向广播
19
+ broadcast: (event: string, data?: any, childIds?: string | string[]) => void;
20
+ broadcastToChildren: (componentName: string, event: string, data?: any) => void;
11
21
  getChildren: () => ChildContext[];
12
22
  getExposed: () => Record<string, any>;
13
23
  getChildExposed: (childId: string) => Record<string, any>;
14
24
  getChildrenExposed: () => Array<{ id: string; name: string; exposed: Record<string, any> }>;
25
+ getInstance: () => any;
15
26
  }
16
27
 
17
28
  interface ChildContext {
@@ -25,7 +36,6 @@ interface ChildContext {
25
36
 
26
37
  // 符号定义
27
38
  const PARENT_CONTEXT_SYMBOL = Symbol('parent_context');
28
- const CHILDREN_CONTEXT_SYMBOL = Symbol('children_context');
29
39
 
30
40
  /**
31
41
  * 生成实例唯一ID
@@ -56,10 +66,36 @@ function findParentInstance(name: string, instance: any): any {
56
66
  */
57
67
  function getParentContext(name: string, instance: any): ParentContext | null {
58
68
  const parentInstance = findParentInstance(name, instance);
59
- if (parentInstance) {
60
- return parentInstance.proxy?.[PARENT_CONTEXT_SYMBOL] || null;
69
+ return parentInstance?.proxy?.[PARENT_CONTEXT_SYMBOL] || null;
70
+ }
71
+
72
+ /**
73
+ * 递归查找所有指定名称的子组件
74
+ */
75
+ function findAllChildComponents(componentName: string, instance: any): any[] {
76
+ const components: any[] = [];
77
+
78
+ function traverse(currentInstance: any) {
79
+ if (!currentInstance?.subTree) return;
80
+
81
+ const subTree = currentInstance.subTree?.children || [];
82
+ const children = Array.isArray(subTree) ? subTree : [subTree];
83
+
84
+ children.forEach((vnode: any) => {
85
+ const child = vnode.component;
86
+ if (!child) return;
87
+
88
+ const name = child.type?.name || child.type?.__name;
89
+ if (name === componentName) {
90
+ components.push(child);
91
+ }
92
+ traverse(child);
93
+ });
61
94
  }
62
- return null;
95
+
96
+ traverse(instance);
97
+ logger.log(`Found ${components.length} ${componentName} components`);
98
+ return components;
63
99
  }
64
100
 
65
101
  /**
@@ -71,27 +107,20 @@ export function useParent(componentName?: string) {
71
107
  throw new Error('useParent must be called within setup function');
72
108
  }
73
109
 
74
- // 使用组件名称作为默认名称
75
110
  const name = componentName || instance.type.name || instance.type.__name;
76
111
  if (!name) {
77
- throw new Error('Component name is required for useParent. Either provide a name or set component name.');
112
+ throw new Error('Component name is required for useParent');
78
113
  }
79
114
 
80
115
  const children = reactive<ChildContext[]>([]);
81
116
  const childrenMap = new Map<string, ChildContext>();
82
117
 
83
- // 修改:增强broadcast方法,支持定向广播
84
118
  const broadcast = (event: string, data?: any, childIds?: string | string[]) => {
85
- let targetChildren: ChildContext[] = [];
86
-
87
- if (childIds) {
88
- // 处理单个childId或childId数组
89
- const ids = Array.isArray(childIds) ? childIds : [childIds];
90
- targetChildren = ids.map(id => childrenMap.get(id)).filter(Boolean) as ChildContext[];
91
- } else {
92
- // 没有指定childIds,广播给所有子组件
93
- targetChildren = Array.from(childrenMap.values());
94
- }
119
+ const targetChildren = childIds
120
+ ? ((Array.isArray(childIds) ? childIds : [childIds])
121
+ .map(id => childrenMap.get(id))
122
+ .filter(Boolean) as ChildContext[])
123
+ : Array.from(childrenMap.values());
95
124
 
96
125
  logger.log(`Parent ${name} broadcasting event: ${event} to ${targetChildren.length} children`);
97
126
 
@@ -101,81 +130,80 @@ export function useParent(componentName?: string) {
101
130
  try {
102
131
  exposed[event](data);
103
132
  } catch (error) {
104
- logger.warn(`Error calling child method ${event} for child ${child.id}:`, error);
133
+ logger.warn(`Error calling child method ${event}:`, error);
105
134
  }
106
135
  }
107
136
  });
108
137
  };
109
138
 
110
- // 父组件上下文
139
+ const broadcastToChildren = (componentName: string, event: string, data?: any) => {
140
+ logger.log(`Parent ${name} broadcasting event: ${event} to all ${componentName} components`);
141
+
142
+ const childComponents = findAllChildComponents(componentName, instance);
143
+ let successCount = 0;
144
+
145
+ childComponents.forEach(childComponent => {
146
+ const exposed = childComponent.exposed || childComponent.proxy;
147
+ if (exposed && typeof exposed[event] === 'function') {
148
+ try {
149
+ exposed[event](data);
150
+ successCount++;
151
+ } catch (error) {
152
+ logger.warn(`Error calling ${componentName} method ${event}:`, error);
153
+ }
154
+ }
155
+ });
156
+
157
+ logger.log(
158
+ `Parent ${name} successfully called ${successCount} of ${childComponents.length} ${componentName} components`
159
+ );
160
+ };
161
+
111
162
  const parentContext: ParentContext = {
112
163
  name,
113
-
114
164
  addChild(child: ChildContext) {
115
165
  if (!childrenMap.has(child.id)) {
116
166
  childrenMap.set(child.id, child);
117
167
  children.push(child);
118
- logger.log(`Parent ${name} added child: ${child.name} (${child.id})`);
168
+ logger.log(`Parent ${name} added child: ${child.name}`);
119
169
  }
120
170
  },
121
-
122
171
  removeChild(childId: string) {
123
172
  if (childrenMap.has(childId)) {
124
173
  const child = childrenMap.get(childId)!;
125
174
  childrenMap.delete(childId);
126
175
  const index = children.findIndex(c => c.id === childId);
127
- if (index > -1) {
128
- children.splice(index, 1);
129
- }
176
+ if (index > -1) children.splice(index, 1);
130
177
  logger.log(`Parent ${name} removed child: ${childId}`);
131
178
  }
132
179
  },
133
-
134
- broadcast, // 使用新的broadcast方法
135
-
136
- getChildren() {
137
- return Array.from(childrenMap.values());
138
- },
139
-
140
- getExposed() {
141
- return instance.exposed || {};
142
- },
143
-
180
+ broadcast,
181
+ broadcastToChildren,
182
+ getChildren: () => Array.from(childrenMap.values()),
183
+ getExposed: () => instance.exposed || {},
144
184
  getChildExposed(childId: string) {
145
185
  const child = childrenMap.get(childId);
146
- if (child && child.getExposed) {
147
- return child.getExposed();
148
- }
149
- logger.warn(`Child ${childId} not found or does not have getExposed method`);
150
- return {};
186
+ return child?.getExposed?.() || {};
151
187
  },
152
-
153
188
  getChildrenExposed() {
154
189
  return Array.from(childrenMap.values())
155
190
  .filter(child => child.getExposed)
156
- .map(child => {
157
- const exposed = child.getExposed();
158
- return {
159
- id: child.id,
160
- name: child.name,
161
- exposed: exposed
162
- };
163
- })
191
+ .map(child => ({
192
+ id: child.id,
193
+ name: child.name,
194
+ exposed: child.getExposed()
195
+ }))
164
196
  .filter(item => Object.keys(item.exposed).length > 0);
165
- }
197
+ },
198
+ getInstance: () => instance
166
199
  };
167
200
 
168
- // 在组件实例上存储父组件上下文
169
201
  if (instance.proxy) {
170
202
  instance.proxy[PARENT_CONTEXT_SYMBOL] = parentContext;
171
203
  }
172
204
 
173
- // 组件卸载时清理
174
205
  onUnmounted(() => {
175
- // 清理所有子组件引用
176
- childrenMap.forEach((child, childId) => {
177
- parentContext.removeChild(childId);
178
- });
206
+ childrenMap.forEach((_, childId) => parentContext.removeChild(childId));
179
207
  if (instance.proxy) {
180
208
  delete instance.proxy[PARENT_CONTEXT_SYMBOL];
181
209
  }
@@ -185,11 +213,13 @@ export function useParent(componentName?: string) {
185
213
  return {
186
214
  parentName: name,
187
215
  children,
188
- broadcast: parentContext.broadcast,
216
+ broadcast,
217
+ broadcastToChildren,
189
218
  getChildren: parentContext.getChildren,
190
219
  getChildExposed: parentContext.getChildExposed,
191
220
  getChildrenExposed: parentContext.getChildrenExposed,
192
- getExposed: parentContext.getExposed
221
+ getExposed: parentContext.getExposed,
222
+ getInstance: parentContext.getInstance
193
223
  };
194
224
  }
195
225
 
@@ -202,18 +232,24 @@ export function useChildren(componentName?: string, parentName?: string) {
202
232
  throw new Error('useChildren must be called within setup function');
203
233
  }
204
234
 
205
- // 使用组件名称作为默认名称
206
235
  const name = componentName || instance.type.name || instance.type.__name;
207
- // 修改:移除强制要求组件名称的报错,允许匿名组件
208
- // if (!name) {
209
- // throw new Error('Component name is required for useChildren. Either provide a name or set component name.');
210
- // }
211
-
212
236
  const instanceId = generateInstanceId(name || 'anonymous');
213
- const parentRef = ref<ParentContext | null>(null);
237
+ const parentRef = ref<any | null>(null);
214
238
  const parentExposed = ref<Record<string, any>>({});
215
239
 
216
- // 获取父组件暴露内容
240
+ const createSimulatedParentContext = (parentInstance: any): ParentContext => ({
241
+ name: parentInstance?.type?.name || parentInstance?.type?.__name || 'unknown',
242
+ addChild: () => logger.log('Simulated parent added child'),
243
+ removeChild: () => logger.log('Simulated parent removed child'),
244
+ broadcast: () => logger.log('Simulated parent broadcasting'),
245
+ broadcastToChildren: () => logger.log('Simulated parent broadcasting to children'),
246
+ getChildren: () => [],
247
+ getExposed: () => parentInstance?.exposed || {},
248
+ getChildExposed: () => ({}),
249
+ getChildrenExposed: () => [],
250
+ getInstance: () => parentInstance
251
+ });
252
+
217
253
  const getParentExposed = (): Record<string, any> => {
218
254
  if (parentRef.value) {
219
255
  const exposed = parentRef.value.getExposed();
@@ -223,94 +259,90 @@ export function useChildren(componentName?: string, parentName?: string) {
223
259
  return {};
224
260
  };
225
261
 
226
- // 获取子组件exposed内容
227
- const getExposed = (): Record<string, any> => {
228
- return instance.exposed || {};
229
- };
262
+ const getExposed = (): Record<string, any> => instance.exposed || {};
230
263
 
231
- // 查找父组件
232
264
  const findParent = (): ParentContext | null => {
233
- // 如果指定了父组件名称,使用精确查找
234
265
  if (parentName) {
235
- return getParentContext(parentName, instance);
266
+ const parentContext = getParentContext(parentName, instance);
267
+ if (parentContext) {
268
+ if (!parentContext.getInstance) {
269
+ parentContext.getInstance = () => findParentInstance(parentName, instance);
270
+ }
271
+ return parentContext;
272
+ }
273
+
274
+ const parentInstance = findParentInstance(parentName, instance);
275
+ if (parentInstance) {
276
+ return createSimulatedParentContext(parentInstance);
277
+ }
236
278
  }
237
279
 
238
- // 否则查找最近的父组件上下文
239
280
  let current = instance.parent;
240
281
  while (current) {
241
282
  const context = current.proxy?.[PARENT_CONTEXT_SYMBOL];
242
283
  if (context) {
284
+ if (!context.getInstance) {
285
+ context.getInstance = () => current;
286
+ }
243
287
  return context;
244
288
  }
245
289
  current = current.parent;
246
290
  }
247
- return null;
291
+
292
+ return instance.parent ? createSimulatedParentContext(instance.parent) : null;
248
293
  };
249
294
 
250
- // 链接到父组件
251
295
  const linkParent = (): boolean => {
252
296
  const parent = findParent();
253
297
  if (parent) {
254
298
  parentRef.value = parent;
255
- parent.addChild(childContext);
299
+ if (parent.addChild && childContext) {
300
+ parent.addChild(childContext);
301
+ }
256
302
  getParentExposed();
257
303
  logger.log(`Child ${name || 'anonymous'} linked to parent ${parent.name}`);
258
304
  return true;
259
305
  }
260
- // 修改:找不到父组件时不报错,只是记录日志
261
306
  logger.log(`Child ${name || 'anonymous'} no parent found, working in standalone mode`);
262
307
  return false;
263
308
  };
264
309
 
265
- // 向父组件发送事件
266
310
  const emitToParent = (event: string, data?: any) => {
267
311
  if (parentRef.value) {
268
- const exposed = parentRef.value.getExposed();
312
+ const exposed = getParentExposed();
269
313
  if (exposed && typeof exposed[event] === 'function') {
270
314
  try {
271
315
  exposed[event](data, instanceId, name);
272
316
  } catch (error) {
273
317
  logger.warn(`Error calling parent method ${event}:`, error);
274
318
  }
275
- } else {
276
- logger.warn(`Parent method ${event} not found or not a function`);
277
319
  }
278
- } else {
279
- // 修改:父组件不存在时只记录调试日志,不报警告
280
- logger.log(`No parent found to emit event: ${event}`);
281
320
  }
282
321
  };
283
322
 
284
- // 子组件上下文
285
323
  const childContext: ChildContext = {
286
324
  id: instanceId,
287
325
  name: name || 'anonymous',
288
326
  emitToParent,
289
327
  getParentExposed,
290
- getInstance() {
291
- return instance;
292
- },
328
+ getInstance: () => instance,
293
329
  getExposed
294
330
  };
295
331
 
296
332
  logger.log(`Child ${name || 'anonymous'} registered, looking for parent`);
297
333
 
298
334
  onMounted(() => {
299
- // 立即尝试连接父组件
300
335
  let connected = linkParent();
301
336
  nextTick(() => {
302
- // 如果未连接成功,500ms后重试一次
337
+ connected = linkParent();
303
338
  if (!connected) {
304
- setTimeout(() => {
305
- linkParent();
306
- }, 500);
339
+ setTimeout(linkParent, 500);
307
340
  }
308
341
  });
309
342
  });
310
343
 
311
- // 组件卸载时清理
312
344
  onUnmounted(() => {
313
- if (parentRef.value) {
345
+ if (parentRef.value?.removeChild) {
314
346
  parentRef.value.removeChild(instanceId);
315
347
  }
316
348
  logger.log(`Child ${name || 'anonymous'} unmounted`);
@@ -338,13 +370,9 @@ export function hasParent(parentName?: string): boolean {
338
370
  return getParentContext(parentName, instance) !== null;
339
371
  }
340
372
 
341
- // 查找最近的父组件上下文
342
373
  let current = instance.parent;
343
374
  while (current) {
344
- const context = current.proxy?.[PARENT_CONTEXT_SYMBOL];
345
- if (context) {
346
- return true;
347
- }
375
+ if (current.proxy?.[PARENT_CONTEXT_SYMBOL]) return true;
348
376
  current = current.parent;
349
377
  }
350
378
  return false;
@@ -355,8 +383,7 @@ export function hasParent(parentName?: string): boolean {
355
383
  */
356
384
  export function getParentContextByName(parentName: string): ParentContext | null {
357
385
  const instance = getCurrentInstance();
358
- if (!instance) return null;
359
- return getParentContext(parentName, instance);
386
+ return instance ? getParentContext(parentName, instance) : null;
360
387
  }
361
388
 
362
389
  /**
@@ -364,7 +391,6 @@ export function getParentContextByName(parentName: string): ParentContext | null
364
391
  */
365
392
  export function cleanupComponentRelations(): void {
366
393
  logger.log('Cleaning up component relations for hot reload');
367
- // 由于使用组件实例存储,热更新时会自动重新建立关系
368
394
  }
369
395
 
370
396
  // 热更新处理
package/libs/index.ts CHANGED
@@ -46,6 +46,8 @@ import throttle from './function/throttle';
46
46
  import getRect from './function/getRect';
47
47
  // 获取父组件
48
48
  import { parentData, parent } from './function/parent';
49
+ // 剪贴板
50
+ import { clipboard } from './function/clipboard';
49
51
  // 配置信息
50
52
  import config from './config/config';
51
53
  // 各个需要fixed的地方的z-index配置文件
@@ -268,6 +270,7 @@ export {
268
270
  $parent,
269
271
  parent,
270
272
  parentData,
273
+ clipboard,
271
274
  dispatch,
272
275
  broadcast,
273
276
  config,
@@ -301,6 +304,7 @@ export const $u = {
301
304
  $parent,
302
305
  parent,
303
306
  parentData,
307
+ clipboard,
304
308
  addUnit,
305
309
  trim,
306
310
  type: ['primary', 'success', 'error', 'warning', 'info'],
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "id": "uview-pro",
3
3
  "name": "uview-pro",
4
4
  "displayName": "【Vue3重构版】uView Pro|基于Vue3+TS全面重构的70+精选UI组件库",
5
- "version": "0.3.2",
5
+ "version": "0.3.3",
6
6
  "description": "uView Pro,是全面支持Vue3的uni-app生态框架,70+精选组件已使用TypeScript重构,已全面支持uni-app Vue3.0",
7
7
  "main": "index.ts",
8
8
  "module": "index.ts",
@@ -91,7 +91,9 @@ declare module 'vue' {
91
91
  uWaterfall: (typeof import('../components/u-waterfall/u-waterfall.vue'))['default'];
92
92
  uText: (typeof import('../components/u-text/u-text.vue'))['default'];
93
93
  uRootPortal: (typeof import('../components/u-root-portal/u-root-portal.vue'))['default'];
94
+ uStatusBar: (typeof import('../components/u-status-bar/u-status-bar.vue'))['default'];
95
+ uSafeBottom: (typeof import('../components/u-safe-bottom/u-safe-bottom.vue'))['default'];
94
96
  }
95
97
  }
96
98
 
97
- export {};
99
+ export { };