uview-pro 0.3.1 → 0.3.2

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,22 @@
1
+ ## 0.3.2(2025-10-15)
2
+
3
+ ### 📝 Documentation | 文档
4
+
5
+ - **changelog:** 更新 CHANGELOG.md 生成配置 ([27a2609](https://github.com/anyup/uView-Pro/commit/27a26095b92cf8cbc6477c563a68b1557f9fb045))
6
+ - 更新交流群图片链接 ([832815d](https://github.com/anyup/uView-Pro/commit/832815deb63f8b144f525591d16e3ccf900b8632))
7
+
8
+ ### ⚡ Performance Improvements | 性能优化
9
+
10
+ - **component-relation:** 增强组件间通信功能;修改 broadcast 方法,支持定向广播;移除对子组件名称的强制要求,允许匿名组件 ([28ea814](https://github.com/anyup/uView-Pro/commit/28ea814810055aa4c99b53d676b16da337fdf7d5))
11
+
12
+ ### 🐛 Bug Fixes | Bug 修复
13
+
14
+ - **u-index-list:** 重构索引锚点组件,兼容多端,修复IndexList索引列表在微信小程序没有吸顶效果 ([ce6a7a3](https://github.com/anyup/uView-Pro/commit/ce6a7a3c01b622cad268779098390c0d593f75bc))
15
+
16
+ ### 👥 Contributors
17
+
18
+ <a href="https://github.com/anyup"><img src="https://github.com/anyup.png?size=40" width="40" height="40" alt="anyup" title="anyup"/></a>
19
+
1
20
  ## 0.3.1(2025-10-14)
2
21
 
3
22
  ### 📝 Documentation | 文档
@@ -31,8 +31,8 @@ export default {
31
31
 
32
32
  <script setup lang="ts">
33
33
  import { IndexAnchorProps } from './types';
34
- import { ref, computed, onMounted, getCurrentInstance } from 'vue';
35
- import { $u } from '../..';
34
+ import { ref, onMounted } from 'vue';
35
+ import { $u, useChildren } from '../..';
36
36
 
37
37
  /**
38
38
  * indexAnchor 索引列表锚点
@@ -46,28 +46,54 @@ import { $u } from '../..';
46
46
  */
47
47
 
48
48
  const props = defineProps(IndexAnchorProps);
49
+ const { parentExposed } = useChildren('u-index-anchor', 'u-index-list');
49
50
 
50
51
  // 响应式变量
51
52
  const active = ref(false);
52
53
  const wrapperStyle = ref<Record<string, any>>({});
53
54
  const anchorStyle = ref<Record<string, any>>({});
54
- let parent: any = null;
55
-
56
- const instance = getCurrentInstance();
55
+ const top = ref(0);
56
+ const height = ref(0);
57
57
 
58
58
  // 挂载时查找父组件并注册
59
59
  onMounted(() => {
60
- parent = $u.$parent('u-index-list', instance);
61
- if (parent) {
62
- parent.exposed?.children.push(instance);
63
- parent.exposed?.updateData();
60
+ if (parentExposed) {
61
+ parentExposed?.value?.updateData();
64
62
  }
65
63
  });
64
+
65
+ function setTop(val) {
66
+ top.value = val;
67
+ }
68
+
69
+ function setHeight(val) {
70
+ height.value = val;
71
+ }
72
+
73
+ function setActive(val) {
74
+ active.value = val;
75
+ }
76
+
77
+ function setAnchorStyle(val) {
78
+ anchorStyle.value = val;
79
+ }
80
+
81
+ function setWrapperStyle(val) {
82
+ wrapperStyle.value = val;
83
+ }
84
+
66
85
  defineExpose({
86
+ props,
87
+ top,
88
+ height,
67
89
  active,
68
90
  wrapperStyle,
69
91
  anchorStyle,
70
- props
92
+ setTop,
93
+ setHeight,
94
+ setActive,
95
+ setAnchorStyle,
96
+ setWrapperStyle
71
97
  });
72
98
  </script>
73
99
 
@@ -49,7 +49,7 @@ export default {
49
49
 
50
50
  <script setup lang="ts">
51
51
  import { ref, reactive, computed, watch, onMounted, getCurrentInstance } from 'vue';
52
- import { $u } from '../..';
52
+ import { $u, useParent } from '../..';
53
53
  import { IndexListProps } from './types';
54
54
 
55
55
  /**
@@ -84,8 +84,6 @@ const activeAnchorIndex = ref(0);
84
84
  const showSidebar = ref(true);
85
85
  const touchmove = ref(false);
86
86
  const touchmoveIndex = ref(0);
87
- // 孩子锚点组件
88
- const children = reactive<any[]>([]);
89
87
  const sidebar = reactive<{ height: number; top: number }>({ height: 0, top: 0 });
90
88
  const scrollToAnchorIndex = ref<number | null>(null);
91
89
  const timer = ref<any>(null);
@@ -101,8 +99,7 @@ const indexList = computed(() => props.indexList ?? getIndexList()).value;
101
99
  const zIndex = computed(() => props.zIndex).value;
102
100
  const activeColor = computed(() => props.activeColor).value;
103
101
 
104
- // 只能在created生命周期定义children,如果在data定义,会因为循环引用而报错
105
- children.length = 0;
102
+ const { children, broadcast } = useParent('u-index-anchor');
106
103
 
107
104
  // 兼容 H5/非H5 stickyOffsetTop
108
105
  onMounted(() => {
@@ -146,11 +143,9 @@ function setRect() {
146
143
  function setAnchorsRect() {
147
144
  return Promise.all(
148
145
  children.map((anchor, index) => {
149
- $u.getRect('.u-index-anchor-wrapper', anchor).then((rect: any) => {
150
- Object.assign(anchor, {
151
- height: rect.height,
152
- top: rect.top
153
- });
146
+ $u.getRect('.u-index-anchor-wrapper', anchor.getInstance()).then((rect: any) => {
147
+ broadcast('setTop', rect.top, anchor.id);
148
+ broadcast('setHeight', rect.height, anchor.id);
154
149
  });
155
150
  })
156
151
  );
@@ -182,9 +177,9 @@ function setSiderbarRect() {
182
177
  function getActiveAnchorIndex() {
183
178
  const sticky = props.sticky;
184
179
  for (let i = children.length - 1; i >= 0; i--) {
185
- const preAnchorHeight = i > 0 ? children[i - 1].height : 0;
180
+ const preAnchorHeight = i > 0 ? children[i - 1].getExposed().height.value : 0;
186
181
  const reachTop = sticky ? preAnchorHeight : 0;
187
- if (reachTop >= children[i].top) {
182
+ if (reachTop >= children[i].getExposed().top.value) {
188
183
  return i;
189
184
  }
190
185
  }
@@ -203,7 +198,7 @@ function onScroll() {
203
198
  if (sticky) {
204
199
  let isActiveAnchorSticky = false;
205
200
  if (active !== -1) {
206
- isActiveAnchorSticky = children[active].top <= 0;
201
+ isActiveAnchorSticky = children[active].getExposed().top.value <= 0;
207
202
  }
208
203
  children.forEach((item, index) => {
209
204
  if (index === active) {
@@ -212,7 +207,7 @@ function onScroll() {
212
207
  color: `${activeColor}`
213
208
  };
214
209
  if (isActiveAnchorSticky) {
215
- wrapperStyle = { height: `${children[index].height}px` };
210
+ wrapperStyle = { height: `${children[index].getExposed().height.value}px` };
216
211
  anchorStyle = {
217
212
  position: 'fixed',
218
213
  top: `${stickyOffsetTop.value}px`,
@@ -220,31 +215,30 @@ function onScroll() {
220
215
  color: `${activeColor}`
221
216
  };
222
217
  }
223
- item.active = active;
224
- item.wrapperStyle = wrapperStyle;
225
- item.anchorStyle = anchorStyle;
218
+ broadcast('setActive', active, item.id);
219
+ broadcast('setAnchorStyle', anchorStyle, item.id);
220
+ broadcast('setWrapperStyle', wrapperStyle, item.id);
226
221
  } else if (index === active - 1) {
227
222
  const currentAnchor = children[index];
228
- const currentOffsetTop = currentAnchor.top;
229
- const targetOffsetTop = index === children.length - 1 ? top.value : children[index + 1].top;
223
+ const currentOffsetTop = currentAnchor.getExposed().top.value;
224
+ const targetOffsetTop =
225
+ index === children.length - 1 ? top.value : children[index + 1].getExposed().top.value;
230
226
  const parentOffsetHeight = targetOffsetTop - currentOffsetTop;
231
- const translateY = parentOffsetHeight - currentAnchor.height;
227
+ const translateY = parentOffsetHeight - currentAnchor.getExposed().height.value;
232
228
  const anchorStyle = {
233
229
  position: 'relative',
234
230
  transform: `translate3d(0, ${translateY}px, 0)`,
235
231
  zIndex: `${zIndex ? zIndex : $u.zIndex.indexListSticky}`,
236
232
  color: `${activeColor}`
237
233
  };
238
- item.active = active;
239
- item.anchorStyle = anchorStyle;
234
+ broadcast('setActive', active, currentAnchor.id);
235
+ broadcast('setAnchorStyle', anchorStyle, currentAnchor.id);
236
+ broadcast('setWrapperStyle', '', item.id);
240
237
  } else {
241
- item.active = false;
242
- item.anchorStyle = '';
243
- item.wrapperStyle = '';
238
+ broadcast('setActive', false, item.id);
239
+ broadcast('setAnchorStyle', '', item.id);
240
+ broadcast('setWrapperStyle', '', item.id);
244
241
  }
245
- item.exposed.active = item.active;
246
- item.exposed.anchorStyle = item.anchorStyle;
247
- item.exposed.wrapperStyle = item.wrapperStyle;
248
242
  });
249
243
  }
250
244
  }
@@ -284,12 +278,12 @@ function scrollToAnchor(index: number) {
284
278
  return;
285
279
  }
286
280
  scrollToAnchorIndex.value = index;
287
- const anchor = children.find(item => item.props.index === indexList[index]);
281
+ const anchor = children.find(item => item.getExposed().props.index === indexList[index]);
288
282
  if (anchor) {
289
- emit('select', anchor.props.index);
283
+ emit('select', anchor.getExposed().props.index);
290
284
  uni.pageScrollTo({
291
285
  duration: 0,
292
- scrollTop: anchor.top + Number(props.scrollTop)
286
+ scrollTop: anchor.getExposed().top.value + Number(props.scrollTop)
293
287
  });
294
288
  }
295
289
  }
@@ -7,7 +7,7 @@ interface ParentContext {
7
7
  name: string;
8
8
  addChild: (child: ChildContext) => void;
9
9
  removeChild: (childId: string) => void;
10
- broadcast: (event: string, data?: any) => void;
10
+ broadcast: (event: string, data?: any, childIds?: string | string[]) => void; // 修改:支持定向广播
11
11
  getChildren: () => ChildContext[];
12
12
  getExposed: () => Record<string, any>;
13
13
  getChildExposed: (childId: string) => Record<string, any>;
@@ -80,6 +80,33 @@ export function useParent(componentName?: string) {
80
80
  const children = reactive<ChildContext[]>([]);
81
81
  const childrenMap = new Map<string, ChildContext>();
82
82
 
83
+ // 修改:增强broadcast方法,支持定向广播
84
+ 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
+ }
95
+
96
+ logger.log(`Parent ${name} broadcasting event: ${event} to ${targetChildren.length} children`);
97
+
98
+ targetChildren.forEach(child => {
99
+ const exposed = child.getExposed();
100
+ if (exposed && typeof exposed[event] === 'function') {
101
+ try {
102
+ exposed[event](data);
103
+ } catch (error) {
104
+ logger.warn(`Error calling child method ${event} for child ${child.id}:`, error);
105
+ }
106
+ }
107
+ });
108
+ };
109
+
83
110
  // 父组件上下文
84
111
  const parentContext: ParentContext = {
85
112
  name,
@@ -104,19 +131,7 @@ export function useParent(componentName?: string) {
104
131
  }
105
132
  },
106
133
 
107
- broadcast(event: string, data?: any) {
108
- logger.log(`Parent ${name} broadcasting event: ${event} to ${childrenMap.size} children`);
109
- childrenMap.forEach(child => {
110
- const exposed = child.getExposed();
111
- if (exposed && typeof exposed[event] === 'function') {
112
- try {
113
- exposed[event](data);
114
- } catch (error) {
115
- logger.warn(`Error calling child method ${event}:`, error);
116
- }
117
- }
118
- });
119
- },
134
+ broadcast, // 使用新的broadcast方法
120
135
 
121
136
  getChildren() {
122
137
  return Array.from(childrenMap.values());
@@ -189,11 +204,12 @@ export function useChildren(componentName?: string, parentName?: string) {
189
204
 
190
205
  // 使用组件名称作为默认名称
191
206
  const name = componentName || instance.type.name || instance.type.__name;
192
- if (!name) {
193
- throw new Error('Component name is required for useChildren. Either provide a name or set component name.');
194
- }
207
+ // 修改:移除强制要求组件名称的报错,允许匿名组件
208
+ // if (!name) {
209
+ // throw new Error('Component name is required for useChildren. Either provide a name or set component name.');
210
+ // }
195
211
 
196
- const instanceId = generateInstanceId(name);
212
+ const instanceId = generateInstanceId(name || 'anonymous');
197
213
  const parentRef = ref<ParentContext | null>(null);
198
214
  const parentExposed = ref<Record<string, any>>({});
199
215
 
@@ -238,9 +254,11 @@ export function useChildren(componentName?: string, parentName?: string) {
238
254
  parentRef.value = parent;
239
255
  parent.addChild(childContext);
240
256
  getParentExposed();
241
- logger.log(`Child ${name} linked to parent ${parent.name}`);
257
+ logger.log(`Child ${name || 'anonymous'} linked to parent ${parent.name}`);
242
258
  return true;
243
259
  }
260
+ // 修改:找不到父组件时不报错,只是记录日志
261
+ logger.log(`Child ${name || 'anonymous'} no parent found, working in standalone mode`);
244
262
  return false;
245
263
  };
246
264
 
@@ -258,14 +276,15 @@ export function useChildren(componentName?: string, parentName?: string) {
258
276
  logger.warn(`Parent method ${event} not found or not a function`);
259
277
  }
260
278
  } else {
261
- logger.warn(`No parent found to emit event: ${event}`);
279
+ // 修改:父组件不存在时只记录调试日志,不报警告
280
+ logger.log(`No parent found to emit event: ${event}`);
262
281
  }
263
282
  };
264
283
 
265
284
  // 子组件上下文
266
285
  const childContext: ChildContext = {
267
286
  id: instanceId,
268
- name,
287
+ name: name || 'anonymous',
269
288
  emitToParent,
270
289
  getParentExposed,
271
290
  getInstance() {
@@ -274,7 +293,7 @@ export function useChildren(componentName?: string, parentName?: string) {
274
293
  getExposed
275
294
  };
276
295
 
277
- logger.log(`Child ${name} registered, looking for parent`);
296
+ logger.log(`Child ${name || 'anonymous'} registered, looking for parent`);
278
297
 
279
298
  onMounted(() => {
280
299
  // 立即尝试连接父组件
@@ -294,12 +313,12 @@ export function useChildren(componentName?: string, parentName?: string) {
294
313
  if (parentRef.value) {
295
314
  parentRef.value.removeChild(instanceId);
296
315
  }
297
- logger.log(`Child ${name} unmounted`);
316
+ logger.log(`Child ${name || 'anonymous'} unmounted`);
298
317
  });
299
318
 
300
319
  return {
301
320
  childId: instanceId,
302
- childName: name,
321
+ childName: name || 'anonymous',
303
322
  parent: parentRef,
304
323
  emitToParent,
305
324
  getParentExposed,
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.1",
5
+ "version": "0.3.2",
6
6
  "description": "uView Pro,是全面支持Vue3的uni-app生态框架,70+精选组件已使用TypeScript重构,已全面支持uni-app Vue3.0",
7
7
  "main": "index.ts",
8
8
  "module": "index.ts",
package/readme.md CHANGED
@@ -73,7 +73,7 @@ pnpm dev
73
73
 
74
74
  <table class="table">
75
75
  <tr>
76
- <td><img src="https://ik.imagekit.io/anyup/images/social/weixin-chat.png?updatedAt=1760233880982" width="250" height="345" ></td>
76
+ <td><img src="https://ik.imagekit.io/anyup/images/social/weixin-chat-cl.png" width="250" height="345" ></td>
77
77
  <td><img src="https://ik.imagekit.io/anyup/images/social/qq-chat.png" width="250" height="345" ></td>
78
78
  </tr>
79
79
  <tr>