uview-pro 0.5.16 → 0.5.18

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.
@@ -1,6 +1,11 @@
1
1
  <template>
2
+ <!-- inline 模式:直接渲染内容,不显示为弹窗 -->
3
+ <view v-if="props.mode === 'inline'" class="u-popup-inline" :class="customClass" :style="inlineStyle">
4
+ <slot />
5
+ </view>
6
+ <!-- 弹窗模式 -->
2
7
  <view
3
- v-if="visibleSync"
8
+ v-else-if="visibleSync"
4
9
  class="u-drawer"
5
10
  :style="$u.toStyle({ zIndex: Number(uZIndex) - 1 }, customStyle)"
6
11
  :class="customClass"
@@ -78,7 +83,7 @@ import { PopupProps } from './types';
78
83
  * popup 弹窗
79
84
  * @description 弹出层容器,用于展示弹窗、信息提示等内容,支持上、下、左、右和中部弹出。组件只提供容器,内部内容由用户自定义
80
85
  * @tutorial https://uviewpro.cn/zh/components/popup.html
81
- * @property {String} mode 弹出方向(默认left
86
+ * @property {String} mode 弹出方向(默认left),新增 inline 模式可直接插入页面
82
87
  * @property {Boolean} mask 是否显示遮罩(默认true)
83
88
  * @property {Stringr | Number} length mode=left | 见官网说明(默认auto)
84
89
  * @property {Boolean} zoom 是否开启缩放动画,只在mode为center时有效(默认true)
@@ -96,6 +101,7 @@ import { PopupProps } from './types';
96
101
  * @event {Function} open 弹出层打开
97
102
  * @event {Function} close 弹出层收起
98
103
  * @example <u-popup v-model="show"><view>出淤泥而不染,濯清涟而不妖</view></u-popup>
104
+ * @example <u-popup mode="inline"><view>直接插入页面内容</view></u-popup>
99
105
  */
100
106
 
101
107
  const props = defineProps(PopupProps);
@@ -106,6 +112,25 @@ const visibleSync = ref(false);
106
112
  const showDrawer = ref(false);
107
113
  const timer = ref<ReturnType<typeof setTimeout> | null>(null);
108
114
  const closeFromInner = ref(false); // value的值改变,是发生在内部还是外部
115
+
116
+ // inline 模式的样式
117
+ const inlineStyle = computed(() => {
118
+ let style: Record<string, any> = {};
119
+ if (props.width) style.width = getUnitValue(props.width);
120
+ if (props.height) style.height = getUnitValue(props.height);
121
+ if (props.borderRadius) style.borderRadius = `${props.borderRadius}rpx`;
122
+ // 合并用户自定义样式
123
+ if (props.customStyle) {
124
+ if (typeof props.customStyle === 'string') {
125
+ // 简单处理字符串样式
126
+ style = { ...style };
127
+ } else {
128
+ Object.assign(style, props.customStyle);
129
+ }
130
+ }
131
+ return style;
132
+ });
133
+
109
134
  // 根据mode的位置,设定其弹窗的宽度(mode = left|right),或者高度(mode = top|bottom)
110
135
  const style = computed(() => {
111
136
  let style: Record<string, any> = {};
@@ -171,6 +196,8 @@ const uZIndex = computed(() => (props.zIndex ? props.zIndex : $u.zIndex.popup));
171
196
  watch(
172
197
  () => props.modelValue,
173
198
  val => {
199
+ // inline 模式下不响应 modelValue 变化
200
+ if (props.mode === 'inline') return;
174
201
  if (val) {
175
202
  open();
176
203
  } else if (!closeFromInner.value) {
@@ -181,6 +208,8 @@ watch(
181
208
  );
182
209
 
183
210
  onMounted(() => {
211
+ // inline 模式下不执行弹窗逻辑
212
+ if (props.mode === 'inline') return;
184
213
  if (props.modelValue) open();
185
214
  });
186
215
 
@@ -203,6 +232,8 @@ function maskClick() {
203
232
  * 关闭弹窗
204
233
  */
205
234
  function close() {
235
+ // inline 模式下不执行关闭逻辑
236
+ if (props.mode === 'inline') return;
206
237
  // 标记关闭是内部发生的,否则修改了value值,导致watch中对value检测,导致再执行一遍close
207
238
  // 造成@close事件触发两次
208
239
  closeFromInner.value = true;
@@ -213,6 +244,8 @@ function close() {
213
244
  * 中部弹出时,点击内容区域关闭弹窗
214
245
  */
215
246
  function modeCenterClose(mode: string) {
247
+ // inline 模式下不执行关闭逻辑
248
+ if (props.mode === 'inline') return;
216
249
  // 中部弹出时,需要.u-drawer-content将居中内容,此元素会铺满屏幕,点击需要关闭弹窗
217
250
  // 让其只在mode=center时起作用
218
251
  if (mode != 'center' || !props.maskCloseAble) return;
@@ -223,6 +256,8 @@ function modeCenterClose(mode: string) {
223
256
  * 打开弹窗
224
257
  */
225
258
  function open() {
259
+ // inline 模式下不执行打开逻辑
260
+ if (props.mode === 'inline') return;
226
261
  change('visibleSync', 'showDrawer', true);
227
262
  }
228
263
 
@@ -232,6 +267,8 @@ function open() {
232
267
  * 打开时,先渲染组件,延时一定时间再让遮罩和弹窗的动画起作用
233
268
  */
234
269
  function change(param1: 'showDrawer' | 'visibleSync', param2: 'visibleSync' | 'showDrawer', status: boolean) {
270
+ // inline 模式下不执行状态变更
271
+ if (props.mode === 'inline') return;
235
272
  // 如果this.popup为false,意味着为picker,actionsheet等组件调用了popup组件
236
273
  if (props.popup === true) {
237
274
  emit('update:modelValue', status);
@@ -262,6 +299,15 @@ function change(param1: 'showDrawer' | 'visibleSync', param2: 'visibleSync' | 's
262
299
  <style scoped lang="scss">
263
300
  @import '../../libs/css/style.components.scss';
264
301
 
302
+ // inline 模式样式
303
+ .u-popup-inline {
304
+ /* #ifndef APP-NVUE */
305
+ display: block;
306
+ /* #endif */
307
+ position: relative;
308
+ background-color: var(--u-bg-white);
309
+ }
310
+
265
311
  .u-drawer {
266
312
  /* #ifndef APP-NVUE */
267
313
  display: block;
@@ -17,7 +17,7 @@
17
17
  :key="index"
18
18
  :class="{ 'u-tabbar__content__circle': props.midButton && item.midButton }"
19
19
  @tap.stop="clickHandler(index)"
20
- :style="{ backgroundColor: props.bgColor }"
20
+ :style="$u.toStyle(getItemStyle(item))"
21
21
  >
22
22
  <view
23
23
  class="u-tabbar__content__item__container"
@@ -32,6 +32,12 @@
32
32
  : 'u-tabbar__content__item__icon'
33
33
  ]"
34
34
  >
35
+ <!-- 凸起按钮边框 -->
36
+ <view
37
+ v-if="props.midButton && item.midButton && props.borderTop"
38
+ class="u-tabbar__content__circle__border"
39
+ :style="{ backgroundColor: props.bgColor }"
40
+ ></view>
35
41
  <u-icon
36
42
  :size="getIconSize(index)"
37
43
  :name="elIconPath(index)"
@@ -69,12 +75,6 @@
69
75
  </view>
70
76
  </view>
71
77
  </view>
72
- <view
73
- v-if="props.midButton"
74
- class="u-tabbar__content__circle__border"
75
- :class="{ 'u-border': props.borderTop }"
76
- :style="{ backgroundColor: props.bgColor, left: midButtonLeft }"
77
- ></view>
78
78
  </view>
79
79
  <!-- 这里加上一个48rpx的高度,是为了增高有凸起按钮时的防塌陷高度(也即按钮凸出来部分的高度) -->
80
80
  <!-- calc 计算0时单位不一致会计算失败,这里+1px -->
@@ -102,6 +102,7 @@ export default {
102
102
  import { ref, computed, onMounted } from 'vue';
103
103
  import { $u } from '../..';
104
104
  import { TabbarProps } from './types';
105
+ import type { TabbarItem } from '../../types/global';
105
106
 
106
107
  /**
107
108
  * u-tabbar 底部导航栏
@@ -128,8 +129,51 @@ const emit = defineEmits<{ (e: 'change', index: number): void; (e: 'update:model
128
129
  // 计算z-index值
129
130
  const uZIndex = computed(() => props?.zIndex ?? $u.zIndex.tabbar);
130
131
 
131
- // 由于安卓太菜了,通过css居中凸起按钮的外层元素有误差,故通过js计算将其居中
132
- const midButtonLeft = ref('50%');
132
+ /**
133
+ * 检查是否有任意item设置了width
134
+ */
135
+ const hasCustomWidth = computed(() => {
136
+ return props.list?.some(item => item.width !== undefined && item.width !== null && item.width !== '') || false;
137
+ });
138
+
139
+ /**
140
+ * 计算每个item的宽度,根据list数量平分
141
+ * 如果任意item设置了width,则不自动计算,返回auto
142
+ */
143
+ const autoItemWidth = computed(() => {
144
+ // 如果用户设置了任意一个width,就不自动计算
145
+ if (hasCustomWidth.value) return 'auto';
146
+
147
+ const count = props.list?.length || 0;
148
+ if (count === 0) return 'auto';
149
+ return `${100 / count}%`;
150
+ });
151
+
152
+ /**
153
+ * 获取单个item的样式
154
+ * 使用 flex 简写属性设置宽度,与原有样式保持一致
155
+ */
156
+ function getItemStyle(item: TabbarItem): Record<string, any> {
157
+ const style: Record<string, any> = {};
158
+ // 背景色
159
+ style.backgroundColor = props.bgColor;
160
+ // flex宽度设置
161
+ if (item.width !== undefined && item.width !== null && item.width !== '') {
162
+ // 固定宽度:不伸缩
163
+ style.flex = `0 0 ${$u.addUnit(item.width)}`;
164
+ style.width = $u.addUnit(item.width);
165
+ } else if (hasCustomWidth.value) {
166
+ // 如果其他item设置了width,未设置的自动填充剩余空间
167
+ style.flex = '1 1 auto';
168
+ style.width = 'auto';
169
+ } else {
170
+ // 自动平分:不伸缩,按百分比分配
171
+ style.flex = `0 0 ${autoItemWidth.value}`;
172
+ style.width = autoItemWidth.value;
173
+ }
174
+ return style;
175
+ }
176
+
133
177
  const pageUrl = ref(''); // 当前页面URL
134
178
 
135
179
  onMounted(() => {
@@ -140,7 +184,6 @@ onMounted(() => {
140
184
  const pages = getCurrentPages();
141
185
  // 页面栈中的最后一个即为项为当前页面,route属性为页面路径
142
186
  pageUrl.value = pages[pages.length - 1].route as string;
143
- if (props.midButton) getMidButtonLeft();
144
187
  });
145
188
 
146
189
  /**
@@ -303,15 +346,6 @@ function getTextSize(index: number) {
303
346
  return props.textSize;
304
347
  }
305
348
 
306
- /**
307
- * 获取凸起按钮外层元素的left值,让其水平居中
308
- */
309
- function getMidButtonLeft() {
310
- const windowWidth = $u.sys().windowWidth;
311
- // 由于安卓中css计算left: 50%的结果不准确,故用js计算
312
- midButtonLeft.value = windowWidth / 2 + 'px';
313
- }
314
-
315
349
  /**
316
350
  * 图标和文字间距
317
351
  */
@@ -358,22 +392,7 @@ function containerStyle(index: number) {
358
392
  /* #ifndef APP-NVUE */
359
393
  box-sizing: content-box;
360
394
  /* #endif */
361
- &__circle__border {
362
- border-radius: 100%;
363
- width: 130rpx;
364
- height: 130rpx;
365
- top: -58rpx;
366
- position: absolute;
367
- z-index: 4;
368
- background-color: var(--u-bg-white);
369
- // 由于安卓的无能,导致只有3个tabbar item时,此css计算方式有误差
370
- // 故使用js计算的形式来定位,此处不注释,是因为js计算有延后,避免出现位置闪动
371
- left: 50%;
372
- transform: translateX(-50%);
373
- &:after {
374
- border-radius: 100px;
375
- }
376
- }
395
+
377
396
  &__item {
378
397
  flex: 1;
379
398
  justify-content: center;
@@ -404,6 +423,7 @@ function containerStyle(index: number) {
404
423
  line-height: 28rpx;
405
424
  text-align: center;
406
425
  width: 100%;
426
+ z-index: 6;
407
427
  }
408
428
  }
409
429
  &__circle {
@@ -440,6 +460,17 @@ function containerStyle(index: number) {
440
460
  z-index: 6;
441
461
  transform: translateX(-50%);
442
462
  }
463
+ &__border {
464
+ position: absolute;
465
+ top: -18rpx;
466
+ width: 130rpx;
467
+ height: 130rpx;
468
+ border-radius: 100%;
469
+ border-top: 1px solid var(--u-border-color);
470
+ background-color: var(--u-bg-white);
471
+ z-index: 0;
472
+ pointer-events: none;
473
+ }
443
474
  }
444
475
  }
445
476
  }
@@ -58,6 +58,6 @@ const thStyle = computed(() => {
58
58
  font-size: 28rpx;
59
59
  color: $u-main-color;
60
60
  font-weight: bold;
61
- background-color: rgb(245, 246, 248);
61
+ background-color: $u-bg-color;
62
62
  }
63
63
  </style>
@@ -97,7 +97,9 @@ export default {
97
97
  fri: 'Fri',
98
98
  sat: 'Sat',
99
99
  confirmText: 'Confirm',
100
- to: ' to '
100
+ to: ' to ',
101
+ holiday: '休',
102
+ workday: '班'
101
103
  },
102
104
  uEmpty: {
103
105
  car: 'Shopping cart is empty',
@@ -97,7 +97,9 @@ export default {
97
97
  fri: '五',
98
98
  sat: '六',
99
99
  confirmText: '确定',
100
- to: '至'
100
+ to: '至',
101
+ holiday: '休',
102
+ workday: '班'
101
103
  },
102
104
  uEmpty: {
103
105
  car: '购物车为空',
package/package.json CHANGED
@@ -2,17 +2,17 @@
2
2
  "id": "uview-pro",
3
3
  "name": "uview-pro",
4
4
  "displayName": "【支持鸿蒙】uView Pro|基于Vue3+TS的高质量UI组件库,支持多主题、暗黑模式、多语言",
5
- "version": "0.5.16",
5
+ "version": "0.5.18",
6
6
  "description": "uView Pro是基于Vue3+TS的多平台UI框架,提供80+高质量组件、便捷工具和常用模板,支持多主题、暗黑模式、多语言,支持H5/APP/鸿蒙/小程序多端开发。已在鸿蒙应用商店上架,欢迎体验!",
7
7
  "main": "index.ts",
8
8
  "module": "index.ts",
9
9
  "browser": "index.ts",
10
10
  "keywords": [
11
- "ui",
12
- "uview",
13
11
  "uview-pro",
14
12
  "vue3",
15
- "typescript"
13
+ "多主题",
14
+ "暗黑模式",
15
+ "多语言"
16
16
  ],
17
17
  "author": "anyup",
18
18
  "license": "MIT",