uview-pro 0.6.2 → 0.6.4

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,18 +1,44 @@
1
- ## 0.6.2(2026-05-15
2
-
3
- ### 🐛 Bug Fixes | Bug 修复
4
-
5
- - **u-checkbox:** 修复多选框在头条、抖音小程序图标偏移的问题 ([8ea1838](https://github.com/anyup/uView-Pro/commit/8ea18383b94b421cabea7d080a6867f4b6133ff5))
6
- - **u-radio:** 修复单选框在头条、抖音小程序图标偏移的问题 ([dd7d6fe](https://github.com/anyup/uView-Pro/commit/dd7d6fee5a22bb39b3dcea9a24b9a06da40ee20e))
1
+ ## 0.6.4(2026-06-02
7
2
 
8
3
  ### ✨ Features | 新功能
9
4
 
10
- - 添加 u-input 组件禁用状态样式 (#155) ([1145d99](https://github.com/anyup/uView-Pro/commit/1145d996ca111da769665ee5dca1bf07a0a1968d))
5
+ - **u-input:** 新增readonly输入属性,支持设置输入框只读状态,新增禁用与只读示例页面及配置项(#160) ([6a92373](https://github.com/anyup/uView-Pro/commit/6a92373a6c8a1c2875b93d6dbb3985df34887c4e))
6
+ - **u-textarea:** 新增click事件支持,在只读/非禁用状态下可触发点击回调,更新演示页面(#160) ([a79dc57](https://github.com/anyup/uView-Pro/commit/a79dc57262bfb3909d2f35bbf26589906e9a4c8d))
7
+ - **u-field:** 新增readonly属性支持,设置后可点击但无法输入,调整disabled和readonly状态的遮罩逻辑与样式(#160) ([708f13b](https://github.com/anyup/uView-Pro/commit/708f13bb3601c0c77a0a75f1b4d1c148f28c7229))
11
8
 
12
9
  ### 👥 Contributors
13
10
 
14
- <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/1361176289"><img src="https://github.com/1361176289.png?size=40" width="40" height="40" alt="小陆同学" title="小陆同学"/></a>
11
+ <a href="https://github.com/anyup"><img src="https://github.com/anyup.png?size=40" width="40" height="40" alt="anyup" title="anyup"/></a>
15
12
 
13
+ ## 0.6.3(2026-05-28)
14
+
15
+ ### 🐛 Bug Fixes | Bug 修复
16
+
17
+ - **u-upload:** 修复进度条显示和上传终止的判断逻辑(#156) ([ad30563](https://github.com/anyup/uView-Pro/commit/ad305638b7e0977c60eda470a682ebb3ecf62c9e))
18
+
19
+ ### ✨ Features | 新功能
20
+
21
+ - **u-dropdown:** 新增fixed定位选项,支持自动适配状态栏和导航栏高度,新增immersive沉浸式模式,增加offsetTop、navbarHeight、zIndex,增强灵活性 ([fc262bd](https://github.com/anyup/uView-Pro/commit/fc262bd5cc078fd3cbb825df2a9066427ccc9b69))
22
+
23
+ ### 👥 Contributors
24
+
25
+ <a href="https://github.com/anyup"><img src="https://github.com/anyup.png?size=40" width="40" height="40" alt="anyup" title="anyup"/></a>
26
+
27
+ ## 0.6.2(2026-05-15)
28
+
29
+ ### 🐛 Bug Fixes | Bug 修复
30
+
31
+ - **u-checkbox:** 修复多选框在头条、抖音小程序图标偏移的问题 ([8ea1838](https://github.com/anyup/uView-Pro/commit/8ea18383b94b421cabea7d080a6867f4b6133ff5))
32
+ - **u-radio:** 修复单选框在头条、抖音小程序图标偏移的问题 ([dd7d6fe](https://github.com/anyup/uView-Pro/commit/dd7d6fee5a22bb39b3dcea9a24b9a06da40ee20e))
33
+
34
+ ### ✨ Features | 新功能
35
+
36
+ - 添加 u-input 组件禁用状态样式 (#155) ([1145d99](https://github.com/anyup/uView-Pro/commit/1145d996ca111da769665ee5dca1bf07a0a1968d))
37
+
38
+ ### 👥 Contributors
39
+
40
+ <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/1361176289"><img src="https://github.com/1361176289.png?size=40" width="40" height="40" alt="小陆同学" title="小陆同学"/></a>
41
+
16
42
  ## 0.6.1(2026-05-13)
17
43
 
18
44
  ### ✨ Features | 新功能
@@ -1,5 +1,6 @@
1
1
  import type { ExtractPropTypes, PropType } from 'vue';
2
2
  import { getColor } from '../../';
3
+ import zIndex from '../../libs/config/zIndex';
3
4
 
4
5
  /**
5
6
  * u-dropdown 下拉菜单 Props
@@ -37,7 +38,30 @@ export const DropdownProps = {
37
38
  /** 菜单右侧的icon图标 */
38
39
  menuIcon: { type: String, default: 'arrow-down' },
39
40
  /** 菜单右侧图标的大小 */
40
- menuIconSize: { type: [Number, String] as PropType<number | string>, default: 26 }
41
+ menuIconSize: { type: [Number, String] as PropType<number | string>, default: 26 },
42
+ /**
43
+ * 是否使用fixed定位,开启后下拉菜单固定在顶部,
44
+ * 自动适配状态栏和导航栏高度,并生成占位区域防止页面塌陷
45
+ */
46
+ fixed: { type: Boolean, default: false },
47
+ /**
48
+ * fixed定位时,在自动计算的偏移量基础上的额外顶部偏移量(px),用于用户微调位置。
49
+ * 实际top = statusBarHeight + navbarHeight + offsetTop
50
+ */
51
+ offsetTop: { type: [Number, String] as PropType<number | string>, default: 0 },
52
+ /**
53
+ * fixed定位时,状态栏和导航栏所占的总高度(px)。
54
+ * 默认不设置(空字符串),组件会自动获取系统状态栏高度 + 默认导航栏高度(44px)。
55
+ * 设置任意数值(包括0)则使用用户指定值,不再自动计算。
56
+ */
57
+ navbarHeight: { type: [Number, String] as PropType<number | string>, default: '' },
58
+ /**
59
+ * 沉浸式模式,仅在fixed下生效。
60
+ * 开启后不生成占位区域,允许页面内容延伸到dropdown下方(类似沉浸式导航栏)
61
+ */
62
+ immersive: { type: Boolean, default: false },
63
+ /** fixed定位时的z-index值 */
64
+ zIndex: { type: [Number, String] as PropType<number | string>, default: zIndex.dropdown }
41
65
  };
42
66
 
43
67
  export type DropdownProps = ExtractPropTypes<typeof DropdownProps>;
@@ -1,63 +1,73 @@
1
1
  <template>
2
- <view class="u-dropdown" :style="$u.toStyle(styles, customStyle)" :class="customClass">
3
- <view
4
- class="u-dropdown__menu"
5
- :style="{ height: $u.addUnit(height) }"
6
- :class="{ 'u-border-bottom': borderBottom }"
7
- >
2
+ <view class="u-dropdown-wrapper">
3
+ <view class="u-dropdown" :style="dropdownRootStyle" :class="[{ 'u-dropdown__fixed': fixed }, customClass]">
8
4
  <view
9
- class="u-dropdown__menu__item"
10
- v-for="(item, index) in menuList"
11
- :key="index"
12
- @tap.stop="menuClick(index)"
5
+ class="u-dropdown__menu"
6
+ :style="{ height: $u.addUnit(height) }"
7
+ :class="{ 'u-border-bottom': borderBottom }"
13
8
  >
14
- <view class="u-flex">
15
- <text
16
- class="u-dropdown__menu__item__text"
17
- :style="{
18
- color: item.disabled
19
- ? 'var(--u-light-color)'
20
- : index === current || highlightIndex == index
21
- ? activeColor
22
- : inactiveColor,
23
- fontSize: $u.addUnit(titleSize)
24
- }"
25
- >{{ item.title }}</text
26
- >
27
- <view
28
- class="u-dropdown__menu__item__arrow"
29
- :class="{
30
- 'u-dropdown__menu__item__arrow--rotate': index === current
31
- }"
32
- >
33
- <u-icon
34
- :custom-style="{ display: 'flex' }"
35
- :name="menuIcon"
36
- :size="$u.addUnit(menuIconSize)"
37
- :color="index === current || highlightIndex == index ? activeColor : 'var(--u-light-color)'"
38
- ></u-icon>
9
+ <view
10
+ class="u-dropdown__menu__item"
11
+ v-for="(item, index) in menuList"
12
+ :key="index"
13
+ @tap.stop="menuClick(index)"
14
+ >
15
+ <view class="u-flex">
16
+ <text
17
+ class="u-dropdown__menu__item__text"
18
+ :style="{
19
+ color: item.disabled
20
+ ? 'var(--u-light-color)'
21
+ : index === current || highlightIndex == index
22
+ ? activeColor
23
+ : inactiveColor,
24
+ fontSize: $u.addUnit(titleSize)
25
+ }"
26
+ >{{ item.title }}</text
27
+ >
28
+ <view
29
+ class="u-dropdown__menu__item__arrow"
30
+ :class="{
31
+ 'u-dropdown__menu__item__arrow--rotate': index === current
32
+ }"
33
+ >
34
+ <u-icon
35
+ :custom-style="{ display: 'flex' }"
36
+ :name="menuIcon"
37
+ :size="$u.addUnit(menuIconSize)"
38
+ :color="
39
+ index === current || highlightIndex == index ? activeColor : 'var(--u-light-color)'
40
+ "
41
+ ></u-icon>
42
+ </view>
39
43
  </view>
40
44
  </view>
41
45
  </view>
42
- </view>
43
- <view
44
- class="u-dropdown__content"
45
- :style="[
46
- contentStyle,
47
- {
48
- transition: `opacity ${Number(duration) / 1000}s linear`,
49
- top: $u.addUnit(height),
50
- height: contentHeight + 'px'
51
- }
52
- ]"
53
- @tap="maskClick"
54
- @touchmove.stop.prevent
55
- >
56
- <view @tap.stop.prevent class="u-dropdown__content__popup" :style="[popupStyle]">
57
- <slot></slot>
46
+ <view
47
+ class="u-dropdown__content"
48
+ :style="[
49
+ contentStyle,
50
+ {
51
+ transition: `opacity ${Number(duration) / 1000}s linear`,
52
+ top: $u.addUnit(height),
53
+ height: contentHeight + 'px'
54
+ }
55
+ ]"
56
+ @tap="maskClick"
57
+ @touchmove.stop.prevent
58
+ >
59
+ <view @tap.stop.prevent class="u-dropdown__content__popup" :style="[popupStyle]">
60
+ <slot></slot>
61
+ </view>
62
+ <view class="u-dropdown__content__mask"></view>
58
63
  </view>
59
- <view class="u-dropdown__content__mask"></view>
60
64
  </view>
65
+ <!-- fixed定位时的占位区域,防止页面内容塌陷 -->
66
+ <view
67
+ v-if="fixed && !immersive"
68
+ class="u-dropdown__placeholder"
69
+ :style="{ height: dropdownPlaceholderHeight + 'px' }"
70
+ ></view>
61
71
  </view>
62
72
  </template>
63
73
 
@@ -75,13 +85,14 @@ export default {
75
85
  </script>
76
86
 
77
87
  <script setup lang="ts">
78
- import { ref, computed, onMounted, getCurrentInstance, nextTick } from 'vue';
88
+ import { ref, computed, onMounted, nextTick } from 'vue';
79
89
  import { $u, useParent } from '../..';
80
90
  import { DropdownProps } from './types';
81
91
 
82
92
  /**
83
93
  * dropdown 下拉菜单
84
- * @description 该组件一般用于向下展开菜单,同时可切换多个选项卡的场景
94
+ * @description 该组件一般用于向下展开菜单,同时可切换多个选项卡的场景。
95
+ * 支持fixed定位,自动适配状态栏和导航栏高度,并提供占位区域防止页面塌陷。
85
96
  * @tutorial https://uviewpro.cn/zh/components/dropdown.html
86
97
  * @property {String} active-color 标题和选项卡选中的颜色(默认主题色primary)
87
98
  * @property {String} inactive-color 标题和选项卡未选中的颜色(默认var(--u-content-color))
@@ -92,9 +103,14 @@ import { DropdownProps } from './types';
92
103
  * @property {String | Number} border-radius 菜单展开内容下方的圆角值,单位任意(默认0)
93
104
  * @property {Boolean} border-bottom 标题菜单是否显示下边框(默认false)
94
105
  * @property {String | Number} title-size 标题的字体大小,单位任意,数值默认为rpx单位(默认28)
106
+ * @property {Boolean} fixed 是否使用fixed定位固定在顶部,自动适配状态栏和导航栏高度(默认false)
107
+ * @property {String | Number} offset-top fixed定位时,在自动计算的偏移量基础上的额外顶部偏移量,单位px(默认0)
108
+ * @property {String | Number} navbar-height fixed定位时,状态栏+导航栏的总高度(px)。不设置则自动获取,设置任意数值(包括0)则使用指定值
109
+ * @property {Boolean} immersive 沉浸式模式,仅在fixed下生效,开启后不生成占位区域(默认false)
110
+ * @property {String | Number} z-index fixed定位时的z-index值(默认985)
95
111
  * @event {Function} open 下拉菜单被打开时触发
96
112
  * @event {Function} close 下拉菜单被关闭时触发
97
- * @example <u-dropdown></u-dropdown>
113
+ * @example <u-dropdown :fixed="true"></u-dropdown>
98
114
  */
99
115
 
100
116
  const props = defineProps(DropdownProps);
@@ -115,14 +131,74 @@ const contentStyle = ref<any>({ zIndex: -1, opacity: 0 });
115
131
  const highlightIndex = ref<number>(99999);
116
132
  // 下拉内容高度
117
133
  const contentHeight = ref<number>(0);
118
- // 子组件引用
119
- const instance = getCurrentInstance();
120
- // 兼容头条样式
121
- const styles = computed(() => {
122
- const style: any = {};
134
+
135
+ // ==================== fixed定位相关 ====================
136
+ // 获取系统状态栏高度
137
+ const systemInfo = uni.getSystemInfoSync();
138
+ const statusBarHeight = ref(0);
139
+ // #ifdef APP-HARMONY || MP-WEIXIN
140
+ const windowInfo = uni.getWindowInfo();
141
+ statusBarHeight.value = windowInfo.statusBarHeight || 0;
142
+ // #endif
143
+ // #ifndef APP-HARMONY || MP-WEIXIN
144
+ statusBarHeight.value = systemInfo.statusBarHeight || 0;
145
+ // #endif
146
+
147
+ // 默认导航栏高度(与 u-navbar 保持一致)
148
+ const defaultNavbarHeight = computed(() => {
149
+ // #ifdef APP || H5
150
+ return 44;
151
+ // #endif
152
+ // #ifdef MP
153
+ return systemInfo.platform === 'ios' ? 44 : 48;
154
+ // #endif
155
+ });
156
+
157
+ /**
158
+ * 计算 fixed 定位时的总偏移高度(px)
159
+ * - 若用户通过 navbarHeight 指定了任意数值(包括0),则使用用户指定值
160
+ * - 否则(空字符串)自动计算:状态栏高度 + 默认导航栏高度
161
+ * - 最后加上 offsetTop 作为额外偏移
162
+ */
163
+ const dropdownOffsetHeight = computed(() => {
164
+ let baseHeight: number;
165
+ if (props.navbarHeight !== '' && props.navbarHeight !== undefined && props.navbarHeight !== null) {
166
+ // 用户手动指定了 navbar 高度(包括0),直接使用
167
+ baseHeight = Number(props.navbarHeight);
168
+ } else {
169
+ // 自动计算:状态栏高度 + 默认导航栏高度
170
+ baseHeight = statusBarHeight.value + defaultNavbarHeight.value;
171
+ }
172
+ // 加上用户设置的额外 offsetTop 偏移
173
+ return baseHeight + Number(props.offsetTop);
174
+ });
175
+
176
+ /**
177
+ * 占位区域高度 = dropdown菜单栏自身高度(px)
178
+ * 不包含状态栏+导航栏偏移,因为页面上已有 navbar 等元素占据该空间
179
+ */
180
+ const dropdownPlaceholderHeight = computed(() => {
181
+ return uni.upx2px(Number(props.height));
182
+ });
183
+
184
+ /**
185
+ * dropdown 根节点样式
186
+ * fixed 时设置 top 和 z-index
187
+ */
188
+ const dropdownRootStyle = computed(() => {
189
+ const style: Record<string, any> = {};
190
+
191
+ // 兼容头条小程序
123
192
  // #ifdef MP-TOUTIAO
124
193
  style.width = '100vw';
125
194
  // #endif
195
+
196
+ // fixed 定位时,计算顶部偏移和 z-index
197
+ if (props.fixed) {
198
+ style.top = dropdownOffsetHeight.value + 'px';
199
+ style.zIndex = props.zIndex ? Number(props.zIndex) : $u.zIndex.dropdown;
200
+ }
201
+
126
202
  return style;
127
203
  });
128
204
 
@@ -193,7 +269,7 @@ function open(index: number) {
193
269
  // 重置高亮索引,否则会造成多个菜单同时高亮
194
270
  // highlightIndex.value = 9999;
195
271
  // 展开时,设置下拉内容的样式
196
- contentStyle.value = { zIndex: 11 };
272
+ contentStyle.value = { zIndex: 11, display: 'block' };
197
273
  // 标记展开状态以及当前展开项的索引
198
274
  active.value = true;
199
275
  current.value = index;
@@ -214,8 +290,12 @@ function close() {
214
290
  // 设置为收起状态,同时current归位,设置为空字符串
215
291
  active.value = false;
216
292
  current.value = 99999;
217
- // 下拉内容的样式进行调整,不透明度设置为0
218
- contentStyle.value = { zIndex: -1, opacity: 0 };
293
+ // 下拉内容的样式进行调整,不透明度设置为0,fixed模式下隐藏display避免遮挡页面元素
294
+ if (props.fixed) {
295
+ contentStyle.value = { zIndex: -1, opacity: 0, display: 'none' };
296
+ } else {
297
+ contentStyle.value = { zIndex: -1, opacity: 0 };
298
+ }
219
299
  }
220
300
 
221
301
  /**
@@ -243,14 +323,15 @@ function highlight(index?: number) {
243
323
  */
244
324
  function getContentHeight() {
245
325
  const windowHeight = $u.sys().windowHeight;
326
+ contentHeight.value = windowHeight;
246
327
 
247
- $u.getRect('.u-dropdown__menu', instance).then((res: any) => {
248
- // 这里获取的是dropdown的尺寸,在H5上,uniapp获取尺寸是有bug的(以前提出修复过,后来又出现了此bug,目前hx2.8.11版本)
249
- // H5端bug表现为元素尺寸的top值为导航栏底部到到元素的上边沿的距离,但是元素的bottom值确是导航栏顶部到元素底部的距离
250
- // 二者是互相矛盾的,本质原因是H5端导航栏非原生,uni的开发者大意造成
251
- // 这里取菜单栏的botton值合理的,不能用res.top,否则页面会造成滚动
252
- contentHeight.value = windowHeight - res.bottom;
253
- });
328
+ // $u.getRect('.u-dropdown__menu', instance).then((res: any) => {
329
+ // // 这里获取的是dropdown的尺寸,在H5上,uniapp获取尺寸是有bug的(以前提出修复过,后来又出现了此bug,目前hx2.8.11版本)
330
+ // // H5端bug表现为元素尺寸的top值为导航栏底部到到元素的上边沿的距离,但是元素的bottom值确是导航栏顶部到元素底部的距离
331
+ // // 二者是互相矛盾的,本质原因是H5端导航栏非原生,uni的开发者大意造成
332
+ // // 这里取菜单栏的botton值合理的,不能用res.top,否则页面会造成滚动
333
+ // contentHeight.value = windowHeight - res.bottom;
334
+ // });
254
335
  }
255
336
 
256
337
  onMounted(() => {
@@ -275,11 +356,26 @@ defineExpose({
275
356
  <style scoped lang="scss">
276
357
  @import '../../libs/css/style.components.scss';
277
358
 
359
+ .u-dropdown-wrapper {
360
+ width: 100%;
361
+ }
362
+
278
363
  .u-dropdown {
279
364
  flex: 1;
280
365
  width: 100%;
281
366
  position: relative;
282
367
 
368
+ &__fixed {
369
+ position: fixed;
370
+ left: 0;
371
+ right: 0;
372
+ background-color: #fff;
373
+ }
374
+
375
+ &__placeholder {
376
+ width: 100%;
377
+ }
378
+
283
379
  &__menu {
284
380
  @include vue-flex;
285
381
  position: relative;
@@ -312,7 +408,6 @@ defineExpose({
312
408
 
313
409
  &__content {
314
410
  position: absolute;
315
- z-index: 8;
316
411
  width: 100%;
317
412
  left: 0px;
318
413
  bottom: 0;
@@ -56,6 +56,8 @@ export const FieldProps = {
56
56
  type: { type: String as PropType<InputType>, default: 'text' },
57
57
  /** 是否不可输入(默认false) */
58
58
  disabled: { type: Boolean, default: false },
59
+ /** 是否只读,禁止输入但可点击,样式不变,可触发click事件(默认false) */
60
+ readonly: { type: Boolean, default: false },
59
61
  /** 最大输入长度,设置为 -1 的时候不限制最大长度(默认140) */
60
62
  maxlength: { type: [Number, String] as PropType<string | number>, default: 140 },
61
63
  /** 设置键盘右下角按钮的文字,仅在type="text"时生效(默认done) */
@@ -1,7 +1,14 @@
1
1
  <template>
2
2
  <view
3
3
  class="u-field"
4
- :class="[{ 'u-border-top': props.borderTop, 'u-border-bottom': props.borderBottom }, customClass]"
4
+ :class="[
5
+ {
6
+ 'u-border-top': props.borderTop,
7
+ 'u-border-bottom': props.borderBottom,
8
+ 'u-field--disabled': props.disabled
9
+ },
10
+ customClass
11
+ ]"
5
12
  :style="$u.toStyle(customStyle)"
6
13
  >
7
14
  <view
@@ -40,6 +47,7 @@
40
47
  :placeholder="String(props.placeholder)"
41
48
  :placeholderStyle="props.placeholderStyle"
42
49
  :disabled="props.disabled"
50
+ :readonly="props.readonly"
43
51
  :maxlength="inputMaxlength"
44
52
  :focus="props.focus"
45
53
  :autoHeight="props.autoHeight"
@@ -48,7 +56,6 @@
48
56
  @blur="onBlur"
49
57
  @focus="onFocus"
50
58
  @confirm="onConfirm"
51
- @tap="fieldClick"
52
59
  />
53
60
  <!-- prettier-ignore -->
54
61
  <input
@@ -61,6 +68,7 @@
61
68
  :placeholder="String(props.placeholder)"
62
69
  :placeholderStyle="props.placeholderStyle"
63
70
  :disabled="props.disabled"
71
+ :readonly="props.readonly"
64
72
  :maxlength="inputMaxlength"
65
73
  :focus="props.focus"
66
74
  :confirmType="props.confirmType"
@@ -68,10 +76,9 @@
68
76
  @blur="onBlur"
69
77
  @input="onInput"
70
78
  @confirm="onConfirm"
71
- @tap="fieldClick"
72
79
  />
73
- <!-- 透明遮罩,只在disabled时显示,用于响应点击事件 -->
74
- <view v-if="props.disabled" class="u-field-disabled-overlay" @tap="fieldClick"></view>
80
+ <!-- 透明遮罩,在disabled或readonly时显示,用于捕获点击事件(原生input设置disabled会阻止点击冒泡) -->
81
+ <view v-if="props.readonly" class="u-field__readonly-overlay" @tap.stop="fieldClick"></view>
75
82
  </view>
76
83
  <u-icon
77
84
  v-if="props.clearable && inputValue !== '' && focused && !props.disabled"
@@ -256,6 +263,7 @@ function rightIconClick() {
256
263
  }
257
264
 
258
265
  function fieldClick() {
266
+ if (props.disabled) return;
259
267
  emit('click');
260
268
  }
261
269
  </script>
@@ -366,7 +374,7 @@ function fieldClick() {
366
374
  position: relative;
367
375
  }
368
376
 
369
- .u-field-disabled-overlay {
377
+ .u-field__readonly-overlay {
370
378
  position: absolute;
371
379
  top: 0;
372
380
  left: 0;
@@ -375,4 +383,15 @@ function fieldClick() {
375
383
  background-color: transparent;
376
384
  z-index: 1;
377
385
  }
386
+
387
+ .u-field--disabled {
388
+ background-color: $u-bg-gray-light;
389
+ }
390
+
391
+ .u-field--disabled .u-textarea-class,
392
+ .u-field--disabled .u-field__input-wrap {
393
+ background-color: transparent;
394
+ color: $u-light-color;
395
+ -webkit-text-fill-color: $u-light-color;
396
+ }
378
397
  </style>
@@ -50,6 +50,11 @@ export const InputProps = {
50
50
  type: Boolean,
51
51
  default: false
52
52
  },
53
+ /** 是否只读,禁止输入但可点击,样式不变,可触发click事件(默认false) */
54
+ readonly: {
55
+ type: Boolean,
56
+ default: false
57
+ },
53
58
  /** 输入框的最大可输入长度(默认140) */
54
59
  maxlength: {
55
60
  type: [Number, String] as PropType<number | string>,
@@ -24,6 +24,7 @@
24
24
  :placeholder="placeholder"
25
25
  :placeholderStyle="getPlaceholderStyle"
26
26
  :disabled="disabled"
27
+ :readonly="readonly"
27
28
  :maxlength="inputMaxlength"
28
29
  :fixed="fixed"
29
30
  :focus="focus"
@@ -49,6 +50,7 @@
49
50
  :placeholder="placeholder"
50
51
  :placeholderStyle="getPlaceholderStyle"
51
52
  :disabled="disabled || type === 'select'"
53
+ :readonly="readonly"
52
54
  :maxlength="inputMaxlength"
53
55
  :focus="focus"
54
56
  :confirmType="confirmType"
@@ -62,7 +64,8 @@
62
64
  @input="handleInput"
63
65
  @confirm="onConfirm"
64
66
  />
65
- <view class="u-input__select-overlay" v-if="type === 'select'" @tap.stop="inputClick"></view>
67
+ <!-- 透明遮罩,在readonly时显示,用于捕获点击事件(原生input设置disabled会阻止点击冒泡) -->
68
+ <view v-if="readonly || type === 'select'" class="u-input__readonly-overlay" @tap.stop="inputClick"></view>
66
69
  <view class="u-input__right-icon u-flex">
67
70
  <view
68
71
  class="u-input__right-icon__clear u-input__right-icon__item"
@@ -347,7 +350,7 @@ defineExpose({
347
350
  @include vue-flex;
348
351
  align-items: center;
349
352
 
350
- &__select-overlay {
353
+ &__readonly-overlay {
351
354
  position: absolute;
352
355
  inset: 0;
353
356
  z-index: 1;
@@ -55,6 +55,8 @@ export const TextareaProps = {
55
55
  confirmType: { type: String as PropType<string>, default: textarea.confirmType },
56
56
  // 是否禁用
57
57
  disabled: { type: Boolean as PropType<boolean>, default: textarea.disabled },
58
+ // 是否只读,禁止输入但可点击,样式不变,可触发click事件
59
+ readonly: { type: Boolean as PropType<boolean>, default: false },
58
60
  // 是否显示统计字数
59
61
  count: { type: Boolean as PropType<boolean>, default: textarea.count },
60
62
  // 是否自动获取焦点,nvue不支持,H5取决于浏览器的实现
@@ -3,7 +3,8 @@
3
3
  class="u-textarea"
4
4
  :class="[
5
5
  {
6
- 'u-textarea--error': validateState
6
+ 'u-textarea--error': validateState,
7
+ 'u-textarea--disabled': props.disabled
7
8
  },
8
9
  textareaClass,
9
10
  customClass
@@ -19,6 +20,7 @@
19
20
  :placeholder-style="getPlaceholderStyle"
20
21
  :placeholder-class="props.placeholderClass"
21
22
  :disabled="props.disabled"
23
+ :readonly="props.readonly"
22
24
  :focus="props.focus"
23
25
  :autoHeight="props.autoHeight"
24
26
  :fixed="props.fixed"
@@ -51,6 +53,8 @@
51
53
  {{ innerValue.length }}/{{ props.maxlength }}
52
54
  </text>
53
55
 
56
+ <!-- 透明遮罩,在readonly时显示,用于捕获点击事件(原生textarea设置disabled会阻止点击冒泡) -->
57
+ <view v-if="props.readonly" class="u-textarea__readonly-overlay" @tap.stop="textareaClick"></view>
54
58
  <view class="u-textarea__right-icon u-flex">
55
59
  <view
56
60
  class="u-textarea__right-icon__clear u-textarea__right-icon__item"
@@ -132,7 +136,8 @@ const emit = defineEmits([
132
136
  'input',
133
137
  'confirm',
134
138
  'keyboardheightchange',
135
- 'change'
139
+ 'change',
140
+ 'click'
136
141
  ]);
137
142
 
138
143
  const { emitToParent } = useChildren('u-textarea', 'u-form-item');
@@ -359,6 +364,11 @@ function onClear(event: any) {
359
364
  valueChange();
360
365
  }
361
366
 
367
+ function textareaClick() {
368
+ if (props.disabled) return;
369
+ emit('click');
370
+ }
371
+
362
372
  defineExpose({
363
373
  onFormItemError
364
374
  });
@@ -374,6 +384,12 @@ defineExpose({
374
384
  @include flex;
375
385
  flex: 1;
376
386
 
387
+ &__readonly-overlay {
388
+ position: absolute;
389
+ inset: 0;
390
+ z-index: 1;
391
+ }
392
+
377
393
  &--border {
378
394
  border-radius: 4px;
379
395
  border: 1px solid $u-border-color;
@@ -51,7 +51,13 @@
51
51
  </text>
52
52
  <!-- 进度条 -->
53
53
  <view
54
- v-if="showProgress && item.progress > 0 && item.progress < 100 && !item.error"
54
+ v-if="
55
+ showProgress &&
56
+ item.progress !== undefined &&
57
+ item.progress > 0 &&
58
+ item.progress < 100 &&
59
+ !item.error
60
+ "
55
61
  class="u-upload-list__progress"
56
62
  >
57
63
  <u-line-progress
@@ -129,7 +135,13 @@
129
135
  </view>
130
136
  <view class="u-upload-grid__progress">
131
137
  <u-line-progress
132
- v-if="showProgress && item.progress > 0 && item.progress !== 100 && !item.error"
138
+ v-if="
139
+ showProgress &&
140
+ item.progress !== undefined &&
141
+ item.progress > 0 &&
142
+ item.progress !== 100 &&
143
+ !item.error
144
+ "
133
145
  :show-percent="false"
134
146
  height="16"
135
147
  :percent="item.progress"
@@ -1059,8 +1071,9 @@ async function executeBeforeRemove(index: number) {
1059
1071
  */
1060
1072
  function handlerDeleteItem(index: number) {
1061
1073
  // 如果文件正在上传中,终止上传任务
1062
- if (lists.value[index].progress < 100 && lists.value[index].progress > 0) {
1063
- typeof lists.value[index].uploadTask != 'undefined' && lists.value[index].uploadTask?.abort?.();
1074
+ const item = lists.value[index];
1075
+ if (item && item.progress !== undefined && item.progress < 100 && item.progress > 0) {
1076
+ typeof item.uploadTask != 'undefined' && item.uploadTask?.abort?.();
1064
1077
  }
1065
1078
  lists.value.splice(index, 1);
1066
1079
  emit('on-remove', index, lists.value, props.index);
@@ -12,6 +12,7 @@ export interface ZIndexConfig {
12
12
  sticky: number;
13
13
  indexListSticky: number;
14
14
  tabbar: number;
15
+ dropdown: number;
15
16
  }
16
17
 
17
18
  const zIndex: ZIndexConfig = {
@@ -24,7 +25,8 @@ const zIndex: ZIndexConfig = {
24
25
  topTips: 975,
25
26
  sticky: 970,
26
27
  indexListSticky: 965,
27
- tabbar: 998
28
+ tabbar: 998,
29
+ dropdown: 985
28
30
  };
29
31
 
30
32
  export default zIndex;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "id": "uview-pro",
3
3
  "name": "uview-pro",
4
4
  "displayName": "【支持鸿蒙】uView Pro|基于Vue3+TS的高质量UI组件库,支持多主题、暗黑模式、多语言",
5
- "version": "0.6.2",
5
+ "version": "0.6.4",
6
6
  "description": "uView Pro是基于Vue3+TS的多平台UI框架,提供80+高质量组件、便捷工具和常用模板,支持多主题、暗黑模式、多语言,支持H5/APP/鸿蒙/小程序多端开发。已在鸿蒙应用商店上架,欢迎体验!",
7
7
  "main": "index.ts",
8
8
  "module": "index.ts",