uview-pro 0.0.1

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 (149) hide show
  1. package/changelog.md +6 -0
  2. package/components/u-action-sheet/u-action-sheet.vue +205 -0
  3. package/components/u-alert-tips/u-alert-tips.vue +241 -0
  4. package/components/u-avatar/u-avatar.vue +220 -0
  5. package/components/u-avatar-cropper/u-avatar-cropper.vue +329 -0
  6. package/components/u-avatar-cropper/weCropper.d.ts +54 -0
  7. package/components/u-avatar-cropper/weCropper.js +1267 -0
  8. package/components/u-avatar-cropper/weCropper.ts +1254 -0
  9. package/components/u-back-top/u-back-top.vue +156 -0
  10. package/components/u-badge/u-badge.vue +189 -0
  11. package/components/u-button/u-button.vue +562 -0
  12. package/components/u-calendar/u-calendar.vue +725 -0
  13. package/components/u-car-keyboard/u-car-keyboard.vue +236 -0
  14. package/components/u-card/u-card.vue +240 -0
  15. package/components/u-cell-group/u-cell-group.vue +56 -0
  16. package/components/u-cell-item/u-cell-item.vue +245 -0
  17. package/components/u-checkbox/u-checkbox.vue +310 -0
  18. package/components/u-checkbox-group/u-checkbox-group.vue +134 -0
  19. package/components/u-circle-progress/u-circle-progress.vue +210 -0
  20. package/components/u-col/u-col.vue +135 -0
  21. package/components/u-collapse/u-collapse.vue +82 -0
  22. package/components/u-collapse-item/u-collapse-item.vue +190 -0
  23. package/components/u-column-notice/u-column-notice.vue +264 -0
  24. package/components/u-count-down/u-count-down.vue +333 -0
  25. package/components/u-count-to/u-count-to.vue +297 -0
  26. package/components/u-divider/u-divider.vue +141 -0
  27. package/components/u-dropdown/u-dropdown.vue +311 -0
  28. package/components/u-dropdown-item/u-dropdown-item.vue +135 -0
  29. package/components/u-empty/u-empty.vue +111 -0
  30. package/components/u-field/u-field.vue +469 -0
  31. package/components/u-form/u-form.vue +162 -0
  32. package/components/u-form-item/u-form-item.vue +476 -0
  33. package/components/u-full-screen/u-full-screen.vue +80 -0
  34. package/components/u-gap/u-gap.vue +48 -0
  35. package/components/u-grid/u-grid.vue +101 -0
  36. package/components/u-grid-item/u-grid-item.vue +136 -0
  37. package/components/u-icon/u-icon.vue +389 -0
  38. package/components/u-image/types.ts +48 -0
  39. package/components/u-image/u-image.vue +218 -0
  40. package/components/u-index-anchor/u-index-anchor.vue +101 -0
  41. package/components/u-index-list/u-index-list.vue +376 -0
  42. package/components/u-input/u-input.vue +462 -0
  43. package/components/u-keyboard/u-keyboard.vue +188 -0
  44. package/components/u-lazy-load/u-lazy-load.vue +288 -0
  45. package/components/u-line/u-line.vue +71 -0
  46. package/components/u-line-progress/u-line-progress.vue +128 -0
  47. package/components/u-link/u-link.vue +87 -0
  48. package/components/u-loading/u-loading.vue +111 -0
  49. package/components/u-loadmore/u-loadmore.vue +205 -0
  50. package/components/u-mask/u-mask.vue +137 -0
  51. package/components/u-message-input/u-message-input.vue +315 -0
  52. package/components/u-modal/u-modal.vue +284 -0
  53. package/components/u-navbar/u-navbar.vue +314 -0
  54. package/components/u-no-network/image.ts +2 -0
  55. package/components/u-no-network/u-no-network.vue +311 -0
  56. package/components/u-notice-bar/u-notice-bar.vue +274 -0
  57. package/components/u-number-box/u-number-box.vue +344 -0
  58. package/components/u-number-keyboard/u-number-keyboard.vue +170 -0
  59. package/components/u-parse/libs/CssHandler.js +100 -0
  60. package/components/u-parse/libs/MpHtmlParser.js +580 -0
  61. package/components/u-parse/libs/config.js +80 -0
  62. package/components/u-parse/libs/handler.wxs +22 -0
  63. package/components/u-parse/libs/trees.vue +505 -0
  64. package/components/u-parse/u-parse.vue +645 -0
  65. package/components/u-picker/u-picker.vue +808 -0
  66. package/components/u-popup/u-popup.vue +404 -0
  67. package/components/u-radio/u-radio.vue +272 -0
  68. package/components/u-radio-group/u-radio-group.vue +116 -0
  69. package/components/u-rate/u-rate.vue +349 -0
  70. package/components/u-read-more/u-read-more.vue +199 -0
  71. package/components/u-row/u-row.vue +95 -0
  72. package/components/u-row-notice/u-row-notice.vue +273 -0
  73. package/components/u-search/u-search.vue +298 -0
  74. package/components/u-section/u-section.vue +175 -0
  75. package/components/u-select/u-select.vue +387 -0
  76. package/components/u-skeleton/u-skeleton.vue +230 -0
  77. package/components/u-slider/u-slider.vue +293 -0
  78. package/components/u-steps/u-steps.vue +200 -0
  79. package/components/u-sticky/u-sticky.vue +189 -0
  80. package/components/u-subsection/u-subsection.vue +388 -0
  81. package/components/u-swipe-action/u-swipe-action.vue +289 -0
  82. package/components/u-swiper/u-swiper.vue +305 -0
  83. package/components/u-switch/u-switch.vue +146 -0
  84. package/components/u-tabbar/u-tabbar.vue +347 -0
  85. package/components/u-table/u-table.vue +104 -0
  86. package/components/u-tabs/u-tabs.vue +322 -0
  87. package/components/u-tabs-swiper/u-tabs-swiper.vue +426 -0
  88. package/components/u-tag/u-tag.vue +270 -0
  89. package/components/u-td/u-td.vue +76 -0
  90. package/components/u-th/u-th.vue +70 -0
  91. package/components/u-time-line/u-time-line.vue +39 -0
  92. package/components/u-time-line-item/u-time-line-item.vue +88 -0
  93. package/components/u-toast/types.ts +4 -0
  94. package/components/u-toast/u-toast.vue +238 -0
  95. package/components/u-top-tips/u-top-tips.vue +118 -0
  96. package/components/u-tr/u-tr.vue +24 -0
  97. package/components/u-upload/u-upload.vue +600 -0
  98. package/components/u-verification-code/u-verification-code.vue +194 -0
  99. package/components/u-waterfall/u-waterfall.vue +186 -0
  100. package/iconfont.css +910 -0
  101. package/index.scss +23 -0
  102. package/index.ts +166 -0
  103. package/libs/config/config.ts +26 -0
  104. package/libs/config/zIndex.ts +37 -0
  105. package/libs/css/color.scss +155 -0
  106. package/libs/css/common.scss +176 -0
  107. package/libs/css/style.components.scss +7 -0
  108. package/libs/css/style.h5.scss +8 -0
  109. package/libs/css/style.mp.scss +72 -0
  110. package/libs/css/style.nvue.scss +3 -0
  111. package/libs/css/style.vue.scss +175 -0
  112. package/libs/function/$parent.ts +22 -0
  113. package/libs/function/addUnit.ts +13 -0
  114. package/libs/function/color.ts +37 -0
  115. package/libs/function/colorGradient.ts +123 -0
  116. package/libs/function/debounce.ts +28 -0
  117. package/libs/function/deepClone.ts +39 -0
  118. package/libs/function/deepMerge.ts +34 -0
  119. package/libs/function/getParent.ts +59 -0
  120. package/libs/function/getRect.ts +26 -0
  121. package/libs/function/guid.ts +42 -0
  122. package/libs/function/md5.ts +397 -0
  123. package/libs/function/parent.ts +21 -0
  124. package/libs/function/queryParams.ts +60 -0
  125. package/libs/function/random.ts +16 -0
  126. package/libs/function/randomArray.ts +11 -0
  127. package/libs/function/route.ts +118 -0
  128. package/libs/function/sys.ts +15 -0
  129. package/libs/function/test.ts +229 -0
  130. package/libs/function/throttle.ts +31 -0
  131. package/libs/function/timeFormat.ts +54 -0
  132. package/libs/function/timeFrom.ts +48 -0
  133. package/libs/function/toast.ts +14 -0
  134. package/libs/function/trim.ts +21 -0
  135. package/libs/function/type2icon.ts +36 -0
  136. package/libs/hooks/useEmitter.ts +77 -0
  137. package/libs/hooks/useParent.ts +29 -0
  138. package/libs/request/index.ts +237 -0
  139. package/libs/store/index.ts +88 -0
  140. package/libs/util/area.ts +1 -0
  141. package/libs/util/async-validator.js +1356 -0
  142. package/libs/util/city.ts +1 -0
  143. package/libs/util/emitter.ts +112 -0
  144. package/libs/util/mitt.ts +118 -0
  145. package/libs/util/parent.ts +20 -0
  146. package/libs/util/province.ts +1 -0
  147. package/package.json +98 -0
  148. package/readme.md +165 -0
  149. package/theme.scss +38 -0
@@ -0,0 +1,314 @@
1
+ <template>
2
+ <view class="">
3
+ <view class="u-navbar" :style="navbarStyle" :class="{ 'u-navbar-fixed': props.isFixed, 'u-border-bottom': props.borderBottom }">
4
+ <view class="u-status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
5
+ <view class="u-navbar-inner" :style="navbarInnerStyle">
6
+ <view class="u-back-wrap" v-if="props.isBack" @tap="goBack">
7
+ <view class="u-icon-wrap">
8
+ <u-icon :name="props.backIconName" :color="props.backIconColor" :size="props.backIconSize"></u-icon>
9
+ </view>
10
+ <view class="u-icon-wrap u-back-text u-line-1" v-if="props.backText" :style="props.backTextStyle">{{ props.backText }}</view>
11
+ </view>
12
+ <view class="u-navbar-content-title" v-if="props.title" :style="titleStyle">
13
+ <view
14
+ class="u-title u-line-1"
15
+ :style="{
16
+ color: props.titleColor,
17
+ fontSize: props.titleSize + 'rpx',
18
+ fontWeight: props.titleBold ? 'bold' : 'normal'
19
+ }"
20
+ >
21
+ {{ props.title }}
22
+ </view>
23
+ </view>
24
+ <view class="u-slot-content">
25
+ <slot></slot>
26
+ </view>
27
+ <view class="u-slot-right">
28
+ <slot name="right"></slot>
29
+ </view>
30
+ </view>
31
+ </view>
32
+ <!-- 解决fixed定位后导航栏塌陷的问题 -->
33
+ <view
34
+ class="u-navbar-placeholder"
35
+ v-if="props.isFixed && !props.immersive"
36
+ :style="{ width: '100%', height: Number(navbarHeight) + Number(statusBarHeight) + 'px' }"
37
+ ></view>
38
+ </view>
39
+ </template>
40
+
41
+ <script setup lang="ts">
42
+ import { ref, computed } from 'vue';
43
+ import { $u } from '../..';
44
+
45
+ defineOptions({ name: 'u-navbar' });
46
+
47
+ /**
48
+ * navbar 自定义导航栏
49
+ * @description 此组件一般用于在特殊情况下,需要自定义导航栏的时候用到,一般建议使用uniapp自带的导航栏。
50
+ * @tutorial https://www.uviewui.com/components/navbar.html
51
+ * @property {String|Number} height 导航栏高度(不包括状态栏高度在内,内部自动加上),注意这里的单位是px(默认44)
52
+ * @property {String} back-icon-color 左边返回图标的颜色(默认#606266)
53
+ * @property {String} back-icon-name 左边返回图标的名称,只能为uView自带的图标(默认arrow-left)
54
+ * @property {String|Number} back-icon-size 左边返回图标的大小,单位rpx(默认30)
55
+ * @property {String} back-text 返回图标右边的辅助提示文字
56
+ * @property {Object} back-text-style 返回图标右边的辅助提示文字的样式,对象形式(默认{ color: '#606266' })
57
+ * @property {String} title 导航栏标题,如设置为空字符,将会隐藏标题占位区域
58
+ * @property {String|Number} title-width 导航栏标题的最大宽度,内容超出会以省略号隐藏,单位rpx(默认250)
59
+ * @property {String} title-color 标题的颜色(默认#606266)
60
+ * @property {String|Number} title-size 导航栏标题字体大小,单位rpx(默认32)
61
+ * @property {Function} custom-back 自定义返回逻辑方法
62
+ * @property {String|Number} z-index 固定在顶部时的z-index值(默认980)
63
+ * @property {Boolean} is-back 是否显示导航栏左边返回图标和辅助文字(默认true)
64
+ * @property {Object} background 导航栏背景设置,见官网说明(默认{ background: '#ffffff' })
65
+ * @property {Boolean} is-fixed 导航栏是否固定在顶部(默认true)
66
+ * @property {Boolean} immersive 沉浸式,允许fixed定位后导航栏塌陷,仅fixed定位下生效(默认false)
67
+ * @property {Boolean} border-bottom 导航栏底部是否显示下边框,如定义了较深的背景颜色,可取消此值(默认true)
68
+ * @example <u-navbar back-text="返回" title="剑未配妥,出门已是江湖"></u-navbar>
69
+ */
70
+ const props = defineProps({
71
+ // 导航栏高度,单位px,非rpx
72
+ height: {
73
+ type: [String, Number],
74
+ default: ''
75
+ },
76
+ // 返回箭头的颜色
77
+ backIconColor: {
78
+ type: String,
79
+ default: '#606266'
80
+ },
81
+ // 左边返回的图标
82
+ backIconName: {
83
+ type: String,
84
+ default: 'nav-back'
85
+ },
86
+ // 左边返回图标的大小,rpx
87
+ backIconSize: {
88
+ type: [String, Number],
89
+ default: '44'
90
+ },
91
+ // 返回的文字提示
92
+ backText: {
93
+ type: String,
94
+ default: ''
95
+ },
96
+ // 返回的文字的 样式
97
+ backTextStyle: {
98
+ type: Object,
99
+ default: () => ({ color: '#606266' })
100
+ },
101
+ // 导航栏标题
102
+ title: {
103
+ type: String,
104
+ default: ''
105
+ },
106
+ // 标题的宽度,如果需要自定义右侧内容,且右侧内容很多时,可能需要减少这个宽度,单位rpx
107
+ titleWidth: {
108
+ type: [String, Number],
109
+ default: '250'
110
+ },
111
+ // 标题的颜色
112
+ titleColor: {
113
+ type: String,
114
+ default: '#606266'
115
+ },
116
+ // 标题字体是否加粗
117
+ titleBold: {
118
+ type: Boolean,
119
+ default: false
120
+ },
121
+ // 标题的字体大小
122
+ titleSize: {
123
+ type: [String, Number],
124
+ default: 32
125
+ },
126
+ isBack: {
127
+ type: [Boolean, String],
128
+ default: true
129
+ },
130
+ // 对象形式,因为用户可能定义一个纯色,或者线性渐变的颜色
131
+ background: {
132
+ type: Object,
133
+ default: () => ({ background: '#ffffff' })
134
+ },
135
+ // 导航栏是否固定在顶部
136
+ isFixed: {
137
+ type: Boolean,
138
+ default: true
139
+ },
140
+ // 是否沉浸式,允许fixed定位后导航栏塌陷,仅fixed定位下生效
141
+ immersive: {
142
+ type: Boolean,
143
+ default: false
144
+ },
145
+ // 是否显示导航栏的下边框
146
+ borderBottom: {
147
+ type: Boolean,
148
+ default: true
149
+ },
150
+ zIndex: {
151
+ type: [String, Number],
152
+ default: ''
153
+ },
154
+ // 自定义返回逻辑
155
+ customBack: {
156
+ type: Function,
157
+ default: null
158
+ }
159
+ });
160
+ // 获取系统状态栏的高度
161
+ const systemInfo = uni.getSystemInfoSync();
162
+ let menuButtonInfo: any = {};
163
+ // 如果是小程序,获取右上角胶囊的尺寸信息,避免导航栏右侧内容与胶囊重叠(支付宝小程序非本API,尚未兼容)
164
+ // #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
165
+ menuButtonInfo = uni.getMenuButtonBoundingClientRect();
166
+ // #endif
167
+
168
+ // 状态栏高度
169
+ const statusBarHeight = ref(systemInfo.statusBarHeight);
170
+
171
+ // 导航栏内部盒子的样式
172
+ const navbarInnerStyle = computed(() => {
173
+ let style: Record<string, any> = {};
174
+ // 导航栏宽度,如果在小程序下,导航栏宽度为胶囊的左边到屏幕左边的距离
175
+ style.height = String(navbarHeight.value) + 'px';
176
+ // 如果是各家小程序,导航栏内部的宽度需要减少右边胶囊的宽度
177
+ // #ifdef MP
178
+ let rightButtonWidth = systemInfo.windowWidth - menuButtonInfo.left;
179
+ style.marginRight = rightButtonWidth + 'px';
180
+ // #endif
181
+ return style;
182
+ });
183
+
184
+ // 整个导航栏的样式
185
+ const navbarStyle = computed(() => {
186
+ let style: Record<string, any> = {};
187
+ style.zIndex = props.zIndex ? props.zIndex : $u.zIndex.navbar;
188
+ // 合并用户传递的背景色对象
189
+ Object.assign(style, props.background);
190
+ return style;
191
+ });
192
+
193
+ // 导航中间的标题的样式
194
+ const titleStyle = computed(() => {
195
+ let style: Record<string, any> = {};
196
+ // #ifndef MP
197
+ style.left = (systemInfo.windowWidth - uni.upx2px(Number(props.titleWidth))) / 2 + 'px';
198
+ style.right = (systemInfo.windowWidth - uni.upx2px(Number(props.titleWidth))) / 2 + 'px';
199
+ // #endif
200
+ // #ifdef MP
201
+ // 此处是为了让标题显示区域即使在小程序有右侧胶囊的情况下也能处于屏幕的中间,是通过绝对定位实现的
202
+ let rightButtonWidth = systemInfo.windowWidth - menuButtonInfo.left;
203
+ style.left = (systemInfo.windowWidth - uni.upx2px(Number(props.titleWidth))) / 2 + 'px';
204
+ style.right = rightButtonWidth - (systemInfo.windowWidth - uni.upx2px(Number(props.titleWidth))) / 2 + rightButtonWidth + 'px';
205
+ // #endif
206
+ style.width = uni.upx2px(Number(props.titleWidth)) + 'px';
207
+ return style;
208
+ });
209
+
210
+ // 转换字符数值为真正的数值
211
+ const navbarHeight = computed(() => {
212
+ // #ifdef APP-PLUS || H5
213
+ return props.height ? props.height : 44;
214
+ // #endif
215
+ // #ifdef MP
216
+ // 小程序特别处理,让导航栏高度 = 胶囊高度 + 两倍胶囊顶部与状态栏底部的距离之差(相当于同时获得了导航栏底部与胶囊底部的距离)
217
+ // 此方法有缺陷,暂不用(会导致少了几个px),采用直接固定值的方式
218
+ // return menuButtonInfo.height + (menuButtonInfo.top - this.statusBarHeight) * 2;//导航高度
219
+ let height = systemInfo.platform == 'ios' ? 44 : 48;
220
+ return props.height ? props.height : height;
221
+ // #endif
222
+ });
223
+
224
+ /**
225
+ * 返回按钮点击事件
226
+ * 如果自定义了点击返回按钮的函数,则执行,否则执行返回逻辑
227
+ */
228
+ function goBack() {
229
+ if (typeof props.customBack === 'function') {
230
+ // 在微信,支付宝等环境(H5正常),会导致父组件定义的customBack()函数体中的this变成子组件的this
231
+ // 通过bind()方法,绑定父组件的this,让this.customBack()的this为父组件的上下文
232
+ // props.customBack.bind($u.$parent.call(getCurrentInstance()?.proxy))();
233
+ props.customBack();
234
+ } else {
235
+ uni.navigateBack();
236
+ }
237
+ }
238
+ </script>
239
+
240
+ <style scoped lang="scss">
241
+ @import '../../libs/css/style.components.scss';
242
+
243
+ .u-navbar {
244
+ width: 100%;
245
+ }
246
+
247
+ .u-navbar-fixed {
248
+ position: fixed;
249
+ left: 0;
250
+ right: 0;
251
+ top: 0;
252
+ z-index: 991;
253
+ }
254
+
255
+ .u-status-bar {
256
+ width: 100%;
257
+ }
258
+
259
+ .u-navbar-inner {
260
+ @include vue-flex;
261
+ justify-content: space-between;
262
+ position: relative;
263
+ align-items: center;
264
+ }
265
+
266
+ .u-back-wrap {
267
+ @include vue-flex;
268
+ align-items: center;
269
+ flex: 1;
270
+ flex-grow: 0;
271
+ padding: 14rpx 14rpx 14rpx 24rpx;
272
+ }
273
+
274
+ .u-back-text {
275
+ padding-left: 4rpx;
276
+ font-size: 30rpx;
277
+ }
278
+
279
+ .u-navbar-content-title {
280
+ @include vue-flex;
281
+ align-items: center;
282
+ justify-content: center;
283
+ flex: 1;
284
+ position: absolute;
285
+ left: 0;
286
+ right: 0;
287
+ height: 60rpx;
288
+ text-align: center;
289
+ flex-shrink: 0;
290
+ }
291
+
292
+ .u-navbar-centent-slot {
293
+ flex: 1;
294
+ }
295
+
296
+ .u-title {
297
+ line-height: 60rpx;
298
+ font-size: 32rpx;
299
+ flex: 1;
300
+ }
301
+
302
+ .u-navbar-right {
303
+ flex: 1;
304
+ @include vue-flex;
305
+ align-items: center;
306
+ justify-content: flex-end;
307
+ }
308
+
309
+ .u-slot-content {
310
+ flex: 1;
311
+ @include vue-flex;
312
+ align-items: center;
313
+ }
314
+ </style>
@@ -0,0 +1,2 @@
1
+ export const imageSrc =
2
+ 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAEYCAMAAABFglBLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6M0U3MjVFMzQwNEY1MTFFQUE4MTNDOUEzMTVBREMxQjIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6M0U3MjVFMzUwNEY1MTFFQUE4MTNDOUEzMTVBREMxQjIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDozRTcyNUUzMjA0RjUxMUVBQTgxM0M5QTMxNUFEQzFCMiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDozRTcyNUUzMzA0RjUxMUVBQTgxM0M5QTMxNUFEQzFCMiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PkHIU9QAAAMAUExURdHW2OWiou7u7tve4dnc3/vw8N3g4sPCwvjn5+jo6M7Q0u6+vtyEhPXY2Li+wuikpPXW1uXo6dba3Pbg4Na5u+qurqqyt/HJydjb3fjo6LrAxO7Bwey1td6MjOrs7fbc3OTn6Maytf7+/vz19eqqqrzCxvzz87a8wLO6vuqxsf78/PDFxenr7L/FyNTY26+2u/z09MjMzqy0udnZ2dvb27G4vMjN0O7v8P339+Ll5u3v8NDS1ODj5frt7bC3vP76+u24uOKamtTW2MTIy9zc3N7e3vPQ0OCTk8DGyfDDw9LR0c7S1LussNbY2fPOztLU1cLHyrK6vvji4vrv78bKzPX29/np6crP0vjk5Ozu78bLzuepqczR1MHFyMDEyOq1tfTS0vP09cLIy9DU173Ex8bGxvHy88/U18vO0LK4vM7OzsTKzcPJzPLMzM/T1sbMz8HJy+7FxbW8wNTW18XKzvb3+MjLzczP0d3e3+Dh4r3Dxtna29zd3rK5vdPU1cfM0Prq6uOenuPm58HGyfHz8/ro6Lq/w8nO0bzCxcrKytjZ2uXm5vTU1LvBxbW7v+rp6eefn/39/eLi4u3t7Ozs7Pj4+Pr6+vX19fHx8erq6vPz8+Xl5ff39+fn5/v7+/z8/PLx8fX09Pb29ri4uOTk5PHw8OPj4/Py8ubm5vn5+e3s7Pb19fTz8/f29tfX1+7t7cvQ0+zr6/Ly8u3t7fr5+efm5quzuOvq6vT19uvr6/j5+a61uuy6uvb39/T09Ojn5+jq6621uvn6+t/i5KyzuPn4+Le+wvv6+s3S1fj4+fDw8OHk5vv7/Pr7++Xk5LS7v7y8vObl5fz9/ff4+OTj48DEx8XJy+Hk5euysu/x8re9wfn5+v38/Pv8/Pr6++vt7uLi4+Pi4ubl5uXk5dPV1tbV1fHMzNPX2e7u7ejn6PT19fX19PDw7/b29f39/vnr6+Hh4a+3u+7t7q61uePi48PHyf35+enp6fLz9PPz8qmxtuDg4N/f3/Dv7////////1cfN/UAAAEAdFJOU////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wBT9wclAAAlqElEQVR42uydCXwUVZrAk5CEJBAQshACCGyjIRwBJR0It6JBGZZBkRtm5PBgFXAXHBghqAMz6LjGTrd9n7lvwn0JQhARxYNxVJTMwcwOM+7uzK6Z3VXcrnTXVr2q6q7urrvfq26c+n4egXTSVfXv993veym4JkklKdoj0IBoogHRgGiiAdGAaKIB0YBoogHRgGiiAdFEA6IBUVuwx+vqet/v1YAkhxwmcNT9gvjnsAYkGcT7eN1TtThe+1TdL2o1IEkg+rrvUV90MF9oQBIqv6ijF4a3d51XA5J4jVVXx3z587ojGpDEm/QwkO9pQJJB2CvksAYk8fJUXT31xZG63ppRTwI5QgcgR35Rd1MDkgxSX1f31P33P1V3i3u936HUyc3edWSsjuEakKRRW3r9kVv+JrRsrwbklpKTnXs+z0wfONOtAUm8rJu55oqfkZ0TOzUgCZS3Zh7s54+S5RqQhNGYMsnPISkakCSiQcjkNzUgasvUDaVsBF1fb9GXd//B0ziliPzjEA2IujLqGRaMST+cawgLNpn4q30aEDV1Va+dYRqzNy00RMoYUmdpQNTzcb8sCtuKH8w9Z4iWLuIbVzQgapmOBedDOO6c0WjgENK2vKwBUUUmvBSiUbrqxwZuOU18d5MGhEe/dI6a2WvIxA0HX1hfvH7V8gUpA9Mz3x/VuVTRLxvwdAhH5aJjBj4hv39QAxIl743ITHm6azBPnOCfVLwlc6pR3upYFbLjvIuDlEUqRYZo38JYS4gVt5rNZhMQO46byksoMeG4w8QIjtvMpJA/wP1EdZ0bKvkitkh555mBA3zSLnBlSFnNnlJvEJJ95ItW3pJAamvtZhy3m/T0g7fhthJGiG+EviYgmEJ/wHFP6GsbnlZSoicoucxmGwHVguPTBz543C9LHky/Jnql1w5KxWGo8KsThsAFYneYMOb5mlnP11ZCrwOPjfgGI8RqsZuZtUOsFmbllFhZP+zEbc8vGcqzMibv7qos3rd7Mg+TrQv2vCVkiLYc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';
@@ -0,0 +1,311 @@
1
+ <template>
2
+ <view class="u-no-network" v-if="!isConnected" :style="{ 'z-index': uZIndex }" @touchmove.stop.prevent="() => {}">
3
+ <view class="u-inner">
4
+ <image class="u-error-icon" :src="image" mode="widthFix"></image>
5
+ <view class="u-tips">
6
+ {{ tips }}
7
+ </view>
8
+ <!-- 只有APP平台,才能跳转设置页,因为需要调用plus环境 -->
9
+ <!-- #ifdef APP-PLUS -->
10
+ <view class="u-to-setting"> 请检查网络,或前往<text class="u-setting-btn" @tap="openSettings">设置</text> </view>
11
+ <!-- #endif -->
12
+ <view class="u-retry" :hover-stay-time="150" @tap="retry" hover-class="u-retry-hover"> 重试 </view>
13
+ </view>
14
+ </view>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import { ref, computed, onMounted } from 'vue';
19
+ import { imageSrc } from './image';
20
+ import { $u } from '../..';
21
+
22
+ defineOptions({ name: 'u-no-network' });
23
+
24
+ /**
25
+ * noNetwork 无网络提示
26
+ * @description 该组件无需任何配置,引入即可,内部自动处理所有功能和事件。
27
+ * @tutorial https://www.uviewui.com/components/noNetwork.html
28
+ * @property {String} tips 没有网络时的提示语(默认哎呀,网络信号丢失)
29
+ * @property {String | Number} zIndex 组件的z-index值(默认1080)
30
+ * @property {String} image 无网络的图片提示,可用的src地址或base64图片
31
+ * @event {Function} retry 用户点击页面的"重试"按钮时触发
32
+ * @example <u-no-network></u-no-network>
33
+ */
34
+
35
+ const props = defineProps({
36
+ /**
37
+ * 页面文字提示
38
+ */
39
+ tips: {
40
+ type: String,
41
+ default: '哎呀,网络信号丢失'
42
+ },
43
+ /**
44
+ * 一个z-index值,用于设置没有网络这个组件的层次,因为页面可能会有其他定位的元素层级过高,导致此组件被覆盖
45
+ */
46
+ zIndex: {
47
+ type: [Number, String],
48
+ default: ''
49
+ },
50
+ /**
51
+ * image 没有网络的图片提示
52
+ */
53
+ image: {
54
+ type: String,
55
+ default: imageSrc
56
+ }
57
+ });
58
+
59
+ const isConnected = ref(true); // 是否有网络连接
60
+ const networkType = ref<string>('none'); // 网络类型
61
+ const isIOS = ref(false); // 是否iOS平台
62
+
63
+ /**
64
+ * 计算z-index,优先使用props,否则取$u.zIndex.noNetwork
65
+ */
66
+ const uZIndex = computed(() => {
67
+ return props.zIndex ? props.zIndex : $u.zIndex.noNetwork;
68
+ });
69
+
70
+ /**
71
+ * 组件挂载时初始化网络监听
72
+ * 保留所有说明注释
73
+ */
74
+ onMounted(() => {
75
+ isIOS.value = uni.getSystemInfoSync().platform === 'ios';
76
+ uni.onNetworkStatusChange(res => {
77
+ isConnected.value = res.isConnected;
78
+ networkType.value = res.networkType;
79
+ });
80
+ uni.getNetworkType({
81
+ success: res => {
82
+ networkType.value = res.networkType;
83
+ if (res.networkType == 'none') {
84
+ isConnected.value = false;
85
+ } else {
86
+ isConnected.value = true;
87
+ }
88
+ }
89
+ });
90
+ });
91
+
92
+ /**
93
+ * 重新检查网络
94
+ * @event retry 用户点击页面的"重试"按钮时触发
95
+ */
96
+ function retry() {
97
+ uni.getNetworkType({
98
+ success: res => {
99
+ networkType.value = res.networkType;
100
+ if (res.networkType == 'none') {
101
+ uni.showToast({
102
+ title: '无网络连接',
103
+ icon: 'none',
104
+ position: 'top'
105
+ });
106
+ isConnected.value = false;
107
+ } else {
108
+ uni.showToast({
109
+ title: '网络已连接',
110
+ icon: 'none',
111
+ position: 'top'
112
+ });
113
+ isConnected.value = true;
114
+ }
115
+ }
116
+ });
117
+ emit('retry');
118
+ }
119
+
120
+ /**
121
+ * 打开系统设置页(仅APP平台)
122
+ */
123
+ function openSettings() {
124
+ if (networkType.value == 'none') {
125
+ openSystemSettings();
126
+ return;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * 打开APP设置页(仅APP平台)
132
+ */
133
+ function openAppSettings() {
134
+ gotoAppSetting();
135
+ }
136
+
137
+ /**
138
+ * 打开系统设置页(仅APP平台)
139
+ */
140
+ function openSystemSettings() {
141
+ // 以下方法来自5+范畴,如需深究,请自行查阅相关文档
142
+ // https://ask.dcloud.net.cn/docs/
143
+ if (isIOS.value) {
144
+ gotoiOSSetting();
145
+ } else {
146
+ gotoAndroidSetting();
147
+ }
148
+ }
149
+
150
+ /**
151
+ * 获取蜂窝网络权限(仅APP平台)
152
+ */
153
+ function network() {
154
+ // 该方法仅供参考,实际使用请查阅5+文档
155
+ let result: number | null = null;
156
+ const cellularData = plus.ios.newObject('CTCellularData');
157
+ const state = cellularData.plusGetAttribute('restrictedState');
158
+ if (state == 0) {
159
+ result = null;
160
+ } else if (state == 2) {
161
+ result = 1;
162
+ } else if (state == 1) {
163
+ result = 2;
164
+ }
165
+ plus.ios.deleteObject(cellularData);
166
+ return result;
167
+ }
168
+
169
+ /**
170
+ * 跳转到APP设置页(仅APP平台)
171
+ */
172
+ function gotoAppSetting() {
173
+ if (isIOS.value) {
174
+ // @ts-ignore
175
+ const UIApplication = plus.ios.import('UIApplication');
176
+ // @ts-ignore
177
+ const application2 = UIApplication.sharedApplication();
178
+ // @ts-ignore
179
+ const NSURL2 = plus.ios.import('NSURL');
180
+ // @ts-ignore
181
+ const setting2 = NSURL2.URLWithString('app-settings:');
182
+ application2.openURL(setting2);
183
+ // @ts-ignore
184
+ plus.ios.deleteObject(setting2);
185
+ // @ts-ignore
186
+ plus.ios.deleteObject(NSURL2);
187
+ // @ts-ignore
188
+ plus.ios.deleteObject(application2);
189
+ } else {
190
+ // @ts-ignore
191
+ const Intent = plus.android.importClass('android.content.Intent');
192
+ // @ts-ignore
193
+ const Settings = plus.android.importClass('android.provider.Settings');
194
+ // @ts-ignore
195
+ const Uri = plus.android.importClass('android.net.Uri');
196
+ // @ts-ignore
197
+ const mainActivity = plus.android.runtimeMainActivity();
198
+ // @ts-ignore
199
+ const intent = new Intent();
200
+ // @ts-ignore
201
+ intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
202
+ // @ts-ignore
203
+ const uri = Uri.fromParts('package', mainActivity.getPackageName(), null);
204
+ intent.setData(uri);
205
+ // @ts-ignore
206
+ mainActivity.startActivity(intent);
207
+ }
208
+ }
209
+
210
+ /**
211
+ * 跳转到iOS设置页(仅APP平台)
212
+ */
213
+ function gotoiOSSetting() {
214
+ // @ts-ignore
215
+ const UIApplication = plus.ios.import('UIApplication');
216
+ // @ts-ignore
217
+ const application2 = UIApplication.sharedApplication();
218
+ // @ts-ignore
219
+ const NSURL2 = plus.ios.import('NSURL');
220
+ // @ts-ignore
221
+ const setting2 = NSURL2.URLWithString('App-prefs:root=General');
222
+ application2.openURL(setting2);
223
+ // @ts-ignore
224
+ plus.ios.deleteObject(setting2);
225
+ // @ts-ignore
226
+ plus.ios.deleteObject(NSURL2);
227
+ // @ts-ignore
228
+ plus.ios.deleteObject(application2);
229
+ }
230
+
231
+ /**
232
+ * 跳转到Android设置页(仅APP平台)
233
+ */
234
+ function gotoAndroidSetting() {
235
+ // @ts-ignore
236
+ const Intent = plus.android.importClass('android.content.Intent');
237
+ // @ts-ignore
238
+ const Settings = plus.android.importClass('android.provider.Settings');
239
+ // @ts-ignore
240
+ const mainActivity = plus.android.runtimeMainActivity();
241
+ // @ts-ignore
242
+ const intent = new Intent(Settings.ACTION_SETTINGS);
243
+ // @ts-ignore
244
+ mainActivity.startActivity(intent);
245
+ }
246
+
247
+ // 组合式API emit
248
+ const emit = defineEmits(['retry']);
249
+
250
+ defineExpose({
251
+ retry,
252
+ openSettings,
253
+ openAppSettings
254
+ });
255
+ </script>
256
+
257
+ <style lang="scss" scoped>
258
+ @import '../../libs/css/style.components.scss';
259
+
260
+ .u-no-network {
261
+ background-color: #fff;
262
+ position: fixed;
263
+ top: 0;
264
+ left: 0;
265
+ right: 0;
266
+ bottom: 0;
267
+ }
268
+
269
+ .u-inner {
270
+ height: 100vh;
271
+ @include vue-flex;
272
+ flex-direction: column;
273
+ align-items: center;
274
+ justify-content: center;
275
+ margin-top: -15%;
276
+ }
277
+
278
+ .u-tips {
279
+ color: $u-tips-color;
280
+ font-size: 28rpx;
281
+ padding: 30rpx 0;
282
+ }
283
+
284
+ .u-error-icon {
285
+ width: 300rpx;
286
+ }
287
+
288
+ .u-to-setting {
289
+ color: $u-light-color;
290
+ font-size: 26rpx;
291
+ }
292
+
293
+ .u-setting-btn {
294
+ font-size: 26rpx;
295
+ color: $u-type-primary;
296
+ }
297
+
298
+ .u-retry {
299
+ margin-top: 30rpx;
300
+ border: 1px solid $u-tips-color;
301
+ color: $u-tips-color;
302
+ font-size: 28rpx;
303
+ padding: 6rpx 30rpx;
304
+ border-radius: 3px;
305
+ }
306
+
307
+ .u-retry-hover {
308
+ color: #fff;
309
+ background-color: $u-tips-color;
310
+ }
311
+ </style>