uview-pro 0.5.4 → 0.5.5
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 +26 -10
- package/components/u-modal/service.ts +29 -0
- package/components/u-modal/types.ts +11 -1
- package/components/u-modal/u-modal.vue +198 -32
- package/components/u-toast/types.ts +3 -1
- package/components/u-toast/u-toast.vue +25 -13
- package/libs/hooks/index.ts +1 -0
- package/libs/hooks/useModal.ts +105 -0
- package/libs/hooks/useToast.ts +16 -13
- package/locale/lang/en-US.ts +2 -0
- package/locale/lang/zh-CN.ts +2 -0
- package/package.json +1 -1
package/changelog.md
CHANGED
|
@@ -1,24 +1,40 @@
|
|
|
1
|
-
## 0.5.
|
|
2
|
-
|
|
3
|
-
### 🐛 Bug Fixes | Bug 修复
|
|
4
|
-
|
|
5
|
-
- **types:** 优化组件库类型定义和代码健壮性 ([e83eac8](https://github.com/anyup/uView-Pro/commit/e83eac8192476dea5e2d4e5b8b3c68b7da992673))
|
|
6
|
-
- **u-navbar:** 修复状态栏高度获取的条件判断,区分鸿蒙、微信小程序和其他 ([b13d112](https://github.com/anyup/uView-Pro/commit/b13d112be80c46f62bfa343a089f2de70a00f774))
|
|
1
|
+
## 0.5.5(2026-02-02)
|
|
7
2
|
|
|
8
3
|
### ✨ Features | 新功能
|
|
9
4
|
|
|
10
|
-
- **u-
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
5
|
+
- **u-toast:** 新增页面级toast功能并优化loading逻辑 ([4eae5b7](https://github.com/anyup/uView-Pro/commit/4eae5b7ef5d4494c4619bee383e62490994b4317))
|
|
6
|
+
- **useModal:** 新增useModal函数式调用API和全局modal功能(#101) ([724edf3](https://github.com/anyup/uView-Pro/commit/724edf3cd69607a6d4e33954f8d2d701f9502ff3))
|
|
7
|
+
- **locale:** 新增语言配置的标签字段label和区域设置字段locale ([49ba6cb](https://github.com/anyup/uView-Pro/commit/49ba6cbea6b53712496e465dd40654af7608a02d))
|
|
13
8
|
|
|
14
9
|
### ♻️ Code Refactoring | 代码重构
|
|
15
10
|
|
|
16
|
-
- **demo:**
|
|
11
|
+
- **demo:** 调整demo演示中吸顶组件默认偏移量为200 ([165da80](https://github.com/anyup/uView-Pro/commit/165da80eb9eec54cf1a5fa8511d82e2b3d11fed1))
|
|
17
12
|
|
|
18
13
|
### 👥 Contributors
|
|
19
14
|
|
|
20
15
|
<a href="https://github.com/anyup"><img src="https://github.com/anyup.png?size=40" width="40" height="40" alt="anyup" title="anyup"/></a>
|
|
21
16
|
|
|
17
|
+
## 0.5.4(2026-01-30)
|
|
18
|
+
|
|
19
|
+
### 🐛 Bug Fixes | Bug 修复
|
|
20
|
+
|
|
21
|
+
- **types:** 优化组件库类型定义和代码健壮性 ([e83eac8](https://github.com/anyup/uView-Pro/commit/e83eac8192476dea5e2d4e5b8b3c68b7da992673))
|
|
22
|
+
- **u-navbar:** 修复状态栏高度获取的条件判断,区分鸿蒙、微信小程序和其他 ([b13d112](https://github.com/anyup/uView-Pro/commit/b13d112be80c46f62bfa343a089f2de70a00f774))
|
|
23
|
+
|
|
24
|
+
### ✨ Features | 新功能
|
|
25
|
+
|
|
26
|
+
- **u-loading:** 增强u-loading的自定义样式功能 ([c9151ce](https://github.com/anyup/uView-Pro/commit/c9151ce4bee44c762bd7970ab280184c730e97b1))
|
|
27
|
+
- **u-toast:** 新增函数式调用API和全局toast功能(#101) ([b8c8fbf](https://github.com/anyup/uView-Pro/commit/b8c8fbff70c14fe0a6106794a638e450cecbeddf))
|
|
28
|
+
- **components:** 优化组件类型安全 ([02b638f](https://github.com/anyup/uView-Pro/commit/02b638f6e251c9b52e5e3ebb1e40d644d895308a))
|
|
29
|
+
|
|
30
|
+
### ♻️ Code Refactoring | 代码重构
|
|
31
|
+
|
|
32
|
+
- **demo:** 移除多余的toast引用 ([67b2677](https://github.com/anyup/uView-Pro/commit/67b26772eb67e9e2b830c95359688b0116395452))
|
|
33
|
+
|
|
34
|
+
### 👥 Contributors
|
|
35
|
+
|
|
36
|
+
<a href="https://github.com/anyup"><img src="https://github.com/anyup.png?size=40" width="40" height="40" alt="anyup" title="anyup"/></a>
|
|
37
|
+
|
|
22
38
|
## 0.5.3(2026-01-26)
|
|
23
39
|
|
|
24
40
|
### ♻️ Code Refactoring | 代码重构
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* u-modal 函数式调用事件名(全平台)
|
|
3
|
+
* @description
|
|
4
|
+
* - useModal() 通过 uni.$emit 派发事件
|
|
5
|
+
* - <u-modal /> 通过 uni.$on 监听事件并转调自身 show/hide
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ModalProps } from './types';
|
|
9
|
+
|
|
10
|
+
// 普通(页面级)modal 事件
|
|
11
|
+
export const U_MODAL_EVENT_SHOW = 'uview-pro:u-modal:show';
|
|
12
|
+
export const U_MODAL_EVENT_HIDE = 'uview-pro:u-modal:hide';
|
|
13
|
+
export const U_MODAL_EVENT_CLEAR_LOADING = 'uview-pro:u-modal:clear-loading';
|
|
14
|
+
|
|
15
|
+
// 全局(App 根部)modal 事件,供 useModal() 使用
|
|
16
|
+
export const U_MODAL_GLOBAL_EVENT_SHOW = 'uview-pro:u-modal:global:show';
|
|
17
|
+
export const U_MODAL_GLOBAL_EVENT_HIDE = 'uview-pro:u-modal:global:hide';
|
|
18
|
+
export const U_MODAL_GLOBAL_EVENT_CLEAR_LOADING = 'uview-pro:u-modal:global:clear-loading';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* u-modal 函数式调用载荷类型
|
|
22
|
+
* @description 完整覆盖 u-modal 的所有 props(除 modelValue 外)
|
|
23
|
+
*/
|
|
24
|
+
export type ModalPayload = Partial<Omit<ModalProps, 'modelValue'>> & {
|
|
25
|
+
/** 确认回调 */
|
|
26
|
+
onConfirm?: () => void;
|
|
27
|
+
/** 取消回调 */
|
|
28
|
+
onCancel?: () => void;
|
|
29
|
+
};
|
|
@@ -33,7 +33,7 @@ export const ModalProps = {
|
|
|
33
33
|
/** 弹窗内容 */
|
|
34
34
|
content: {
|
|
35
35
|
type: String,
|
|
36
|
-
default:
|
|
36
|
+
default: ''
|
|
37
37
|
},
|
|
38
38
|
/** 是否显示标题 */
|
|
39
39
|
showTitle: {
|
|
@@ -114,6 +114,16 @@ export const ModalProps = {
|
|
|
114
114
|
negativeTop: {
|
|
115
115
|
type: [String, Number] as PropType<number | string>,
|
|
116
116
|
default: 0
|
|
117
|
+
},
|
|
118
|
+
/** 是否作为全局根部 modal(通常放在 App.vue 中,给 useModal() 使用) */
|
|
119
|
+
global: {
|
|
120
|
+
type: Boolean,
|
|
121
|
+
default: false
|
|
122
|
+
},
|
|
123
|
+
/** 是否作为页面级 modal(通常放在页面中,给 useModal({ page: true }) 使用) */
|
|
124
|
+
page: {
|
|
125
|
+
type: Boolean,
|
|
126
|
+
default: false
|
|
117
127
|
}
|
|
118
128
|
};
|
|
119
129
|
|
|
@@ -1,50 +1,61 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<view>
|
|
3
3
|
<u-popup
|
|
4
|
-
|
|
4
|
+
v-model="popupValue"
|
|
5
5
|
mode="center"
|
|
6
|
+
:zoom="effectiveConfig.zoom"
|
|
6
7
|
:popup="false"
|
|
7
8
|
:z-index="uZIndex"
|
|
8
|
-
|
|
9
|
-
:
|
|
10
|
-
:
|
|
11
|
-
:
|
|
9
|
+
:length="effectiveConfig.width"
|
|
10
|
+
:mask-close-able="effectiveConfig.maskCloseAble"
|
|
11
|
+
:border-radius="effectiveConfig.borderRadius"
|
|
12
|
+
:negative-top="effectiveConfig.negativeTop"
|
|
13
|
+
:custom-class="effectiveConfig.customClass"
|
|
12
14
|
@close="popupClose"
|
|
13
|
-
:negative-top="negativeTop"
|
|
14
|
-
:custom-class="customClass"
|
|
15
15
|
>
|
|
16
|
-
<view class="u-model" :style="$u.toStyle(customStyle)">
|
|
17
|
-
<view
|
|
16
|
+
<view class="u-model" :style="$u.toStyle(effectiveConfig.customStyle)">
|
|
17
|
+
<view
|
|
18
|
+
v-if="effectiveConfig.showTitle"
|
|
19
|
+
class="u-model__title u-line-1"
|
|
20
|
+
:style="$u.toStyle(effectiveConfig.titleStyle)"
|
|
21
|
+
>
|
|
22
|
+
{{ effectiveConfig.title }}
|
|
23
|
+
</view>
|
|
18
24
|
<view class="u-model__content">
|
|
19
|
-
<view
|
|
25
|
+
<view v-if="slots.default" :style="$u.toStyle(effectiveConfig.contentStyle)">
|
|
20
26
|
<slot />
|
|
21
27
|
</view>
|
|
22
|
-
<view v-else class="u-model__content__message" :style="
|
|
28
|
+
<view v-else class="u-model__content__message" :style="$u.toStyle(effectiveConfig.contentStyle)">
|
|
29
|
+
{{ effectiveConfig.content }}
|
|
30
|
+
</view>
|
|
23
31
|
</view>
|
|
24
|
-
<view
|
|
32
|
+
<view
|
|
33
|
+
v-if="effectiveConfig.showCancelButton || effectiveConfig.showConfirmButton"
|
|
34
|
+
class="u-model__footer u-border-top"
|
|
35
|
+
>
|
|
25
36
|
<view
|
|
26
|
-
v-if="showCancelButton"
|
|
37
|
+
v-if="effectiveConfig.showCancelButton"
|
|
27
38
|
:hover-stay-time="100"
|
|
28
39
|
hover-class="u-model__btn--hover"
|
|
29
40
|
class="u-model__footer__button"
|
|
30
|
-
:style="
|
|
41
|
+
:style="$u.toStyle(cancelBtnStyle)"
|
|
31
42
|
@tap="cancel"
|
|
32
43
|
>
|
|
33
|
-
{{ cancelText }}
|
|
44
|
+
{{ effectiveConfig.cancelText }}
|
|
34
45
|
</view>
|
|
35
46
|
<view
|
|
36
|
-
v-if="showConfirmButton || slots['confirm-button']"
|
|
37
|
-
:hover-stay-time="100"
|
|
38
|
-
:hover-class="asyncClose ? 'none' : 'u-model__btn--hover'"
|
|
47
|
+
v-if="effectiveConfig.showConfirmButton || slots['confirm-button']"
|
|
39
48
|
class="u-model__footer__button hairline-left"
|
|
49
|
+
:hover-stay-time="100"
|
|
50
|
+
:hover-class="effectiveConfig.asyncClose ? 'none' : 'u-model__btn--hover'"
|
|
40
51
|
:style="[confirmBtnStyle]"
|
|
41
52
|
@tap="confirm"
|
|
42
53
|
>
|
|
43
54
|
<slot v-if="slots['confirm-button']" name="confirm-button"></slot>
|
|
44
55
|
<template v-else>
|
|
45
|
-
<u-loading mode="circle" :color="confirmColor" v-if="loading"></u-loading>
|
|
56
|
+
<u-loading mode="circle" :color="effectiveConfig.confirmColor" v-if="loading"></u-loading>
|
|
46
57
|
<template v-else>
|
|
47
|
-
{{ confirmText }}
|
|
58
|
+
{{ effectiveConfig.confirmText }}
|
|
48
59
|
</template>
|
|
49
60
|
</template>
|
|
50
61
|
</view>
|
|
@@ -68,9 +79,18 @@ export default {
|
|
|
68
79
|
</script>
|
|
69
80
|
|
|
70
81
|
<script setup lang="ts">
|
|
71
|
-
import { ref, computed, watch, useSlots } from 'vue';
|
|
82
|
+
import { ref, computed, watch, onMounted, onBeforeUnmount, useSlots } from 'vue';
|
|
72
83
|
import { $u } from '../..';
|
|
73
84
|
import { ModalProps } from './types';
|
|
85
|
+
import {
|
|
86
|
+
U_MODAL_EVENT_CLEAR_LOADING,
|
|
87
|
+
U_MODAL_EVENT_HIDE,
|
|
88
|
+
U_MODAL_EVENT_SHOW,
|
|
89
|
+
U_MODAL_GLOBAL_EVENT_CLEAR_LOADING,
|
|
90
|
+
U_MODAL_GLOBAL_EVENT_HIDE,
|
|
91
|
+
U_MODAL_GLOBAL_EVENT_SHOW,
|
|
92
|
+
type ModalPayload
|
|
93
|
+
} from './service';
|
|
74
94
|
|
|
75
95
|
/**
|
|
76
96
|
* modal 模态框
|
|
@@ -108,23 +128,99 @@ const slots = useSlots();
|
|
|
108
128
|
|
|
109
129
|
// 确认按钮是否正在加载中
|
|
110
130
|
const loading = ref(false);
|
|
131
|
+
const isGlobal = computed(() => props.global);
|
|
132
|
+
const isPage = computed(() => props.page);
|
|
133
|
+
const showEvent = computed(() => (isGlobal.value ? U_MODAL_GLOBAL_EVENT_SHOW : isPage.value ? U_MODAL_EVENT_SHOW : ''));
|
|
134
|
+
const hideEvent = computed(() => (isGlobal.value ? U_MODAL_GLOBAL_EVENT_HIDE : isPage.value ? U_MODAL_EVENT_HIDE : ''));
|
|
135
|
+
const clearLoadingEvent = computed(() =>
|
|
136
|
+
isGlobal.value ? U_MODAL_GLOBAL_EVENT_CLEAR_LOADING : isPage.value ? U_MODAL_EVENT_CLEAR_LOADING : ''
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
// 存储用户传入的回调函数
|
|
140
|
+
let userOnConfirm: (() => void) | null = null;
|
|
141
|
+
let userOnCancel: (() => void) | null = null;
|
|
142
|
+
|
|
143
|
+
// 需要与 effectiveConfig 合并的 props 键名列表(用于函数式调用)
|
|
144
|
+
const MERGE_PROPS_KEYS = [
|
|
145
|
+
'title',
|
|
146
|
+
'content',
|
|
147
|
+
'showTitle',
|
|
148
|
+
'showConfirmButton',
|
|
149
|
+
'showCancelButton',
|
|
150
|
+
'confirmText',
|
|
151
|
+
'cancelText',
|
|
152
|
+
'confirmColor',
|
|
153
|
+
'cancelColor',
|
|
154
|
+
'confirmStyle',
|
|
155
|
+
'cancelStyle',
|
|
156
|
+
'titleStyle',
|
|
157
|
+
'contentStyle',
|
|
158
|
+
'asyncClose',
|
|
159
|
+
'borderRadius',
|
|
160
|
+
'width',
|
|
161
|
+
'zoom',
|
|
162
|
+
'maskCloseAble',
|
|
163
|
+
'negativeTop',
|
|
164
|
+
'zIndex',
|
|
165
|
+
'customStyle',
|
|
166
|
+
'customClass'
|
|
167
|
+
] as const;
|
|
168
|
+
|
|
169
|
+
// 函数式调用时的临时配置
|
|
170
|
+
const tempConfig = ref<Partial<ModalPayload>>({});
|
|
171
|
+
|
|
172
|
+
// 函数式调用时的内部显示状态(用于 global 模式)
|
|
173
|
+
const internalShow = ref(false);
|
|
111
174
|
|
|
175
|
+
// 有效的配置(函数式调用时合并 tempConfig 和 props,v-model 时使用 props)
|
|
176
|
+
const effectiveConfig = computed(() => {
|
|
177
|
+
// 如果有临时配置(函数式调用),合并用户配置与 props 默认值
|
|
178
|
+
if (Object.keys(tempConfig.value).length > 0) {
|
|
179
|
+
const result: Record<string, any> = {};
|
|
180
|
+
for (const key of MERGE_PROPS_KEYS) {
|
|
181
|
+
// 用户配置优先,否则使用 props 默认值
|
|
182
|
+
result[key] = (tempConfig.value as Record<string, any>)[key] ?? (props as Record<string, any>)[key];
|
|
183
|
+
}
|
|
184
|
+
result.zIndex = tempConfig.value.zIndex ?? props.zIndex ?? $u.zIndex.popup;
|
|
185
|
+
return result;
|
|
186
|
+
}
|
|
187
|
+
// v-model 直接控制时使用 props
|
|
188
|
+
return props;
|
|
189
|
+
});
|
|
190
|
+
// 取消按钮样式
|
|
112
191
|
const cancelBtnStyle = computed(() => {
|
|
113
|
-
return Object.assign({ color:
|
|
192
|
+
return Object.assign({ color: effectiveConfig.value.cancelColor }, effectiveConfig.value.cancelStyle);
|
|
114
193
|
});
|
|
194
|
+
// 确认按钮样式
|
|
115
195
|
const confirmBtnStyle = computed(() => {
|
|
116
|
-
return Object.assign({ color:
|
|
196
|
+
return Object.assign({ color: effectiveConfig.value.confirmColor }, effectiveConfig.value.confirmStyle);
|
|
117
197
|
});
|
|
118
|
-
|
|
119
|
-
|
|
198
|
+
// 弹窗的样式
|
|
199
|
+
const uZIndex = computed(() => effectiveConfig.value.zIndex ?? $u.zIndex.popup);
|
|
200
|
+
// 是否使用内部状态控制显示(global 模式)
|
|
201
|
+
const useInternalShow = computed(() => isGlobal.value || isPage.value);
|
|
202
|
+
// 最终显示状态
|
|
203
|
+
const finalShow = computed(() => {
|
|
204
|
+
if (useInternalShow.value) {
|
|
205
|
+
return internalShow.value;
|
|
206
|
+
}
|
|
207
|
+
return props.modelValue;
|
|
208
|
+
});
|
|
209
|
+
// u-popup 绑定的值
|
|
120
210
|
const popupValue = computed({
|
|
121
|
-
get: () =>
|
|
122
|
-
set: (val: boolean) =>
|
|
211
|
+
get: () => finalShow.value,
|
|
212
|
+
set: (val: boolean) => {
|
|
213
|
+
if (useInternalShow.value) {
|
|
214
|
+
internalShow.value = val;
|
|
215
|
+
} else {
|
|
216
|
+
emit('update:modelValue', val);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
123
219
|
});
|
|
124
220
|
|
|
125
221
|
// 如果是异步关闭时,外部修改v-model的值为false时,重置内部的loading状态,避免下次打开的时候,状态混乱
|
|
126
222
|
watch(
|
|
127
|
-
() =>
|
|
223
|
+
() => popupValue.value,
|
|
128
224
|
n => {
|
|
129
225
|
if (n === true) loading.value = false;
|
|
130
226
|
}
|
|
@@ -134,21 +230,33 @@ watch(
|
|
|
134
230
|
* 确认按钮点击事件
|
|
135
231
|
*/
|
|
136
232
|
function confirm() {
|
|
233
|
+
// 先调用回调,再重置配置
|
|
234
|
+
const onConfirm = userOnConfirm;
|
|
137
235
|
// 异步关闭
|
|
138
|
-
if (
|
|
236
|
+
if (effectiveConfig.value.asyncClose) {
|
|
139
237
|
loading.value = true;
|
|
140
238
|
} else {
|
|
141
|
-
|
|
239
|
+
popupValue.value = false;
|
|
240
|
+
// 延迟重置配置,避免闪屏
|
|
241
|
+
setTimeout(() => resetTempConfig(), 300);
|
|
142
242
|
}
|
|
143
243
|
emit('confirm');
|
|
244
|
+
// 调用函数式调用时用户传入的回调
|
|
245
|
+
onConfirm?.();
|
|
144
246
|
}
|
|
145
247
|
|
|
146
248
|
/**
|
|
147
249
|
* 取消按钮点击事件
|
|
148
250
|
*/
|
|
149
251
|
function cancel() {
|
|
252
|
+
// 先调用回调,再重置配置
|
|
253
|
+
const onCancel = userOnCancel;
|
|
254
|
+
// 延迟重置配置,避免闪屏
|
|
255
|
+
setTimeout(() => resetTempConfig(), 300);
|
|
150
256
|
emit('cancel');
|
|
151
|
-
|
|
257
|
+
popupValue.value = false;
|
|
258
|
+
// 调用函数式调用时用户传入的回调
|
|
259
|
+
onCancel?.();
|
|
152
260
|
// 目前popup弹窗关闭有一个延时操作,此处做一个延时
|
|
153
261
|
// 避免确认按钮文字变成了"确定"字样,modal还没消失,造成视觉不好的效果
|
|
154
262
|
setTimeout(() => {
|
|
@@ -160,7 +268,8 @@ function cancel() {
|
|
|
160
268
|
* 点击遮罩关闭modal,设置v-model的值为false,否则无法第二次弹起modal
|
|
161
269
|
*/
|
|
162
270
|
function popupClose() {
|
|
163
|
-
|
|
271
|
+
popupValue.value = false;
|
|
272
|
+
resetTempConfig();
|
|
164
273
|
}
|
|
165
274
|
|
|
166
275
|
/**
|
|
@@ -170,6 +279,63 @@ function clearLoading() {
|
|
|
170
279
|
loading.value = false;
|
|
171
280
|
}
|
|
172
281
|
|
|
282
|
+
/**
|
|
283
|
+
* 函数式调用显示 modal
|
|
284
|
+
*/
|
|
285
|
+
function onServiceShow(payload: ModalPayload) {
|
|
286
|
+
// 保存回调函数
|
|
287
|
+
userOnConfirm = payload.onConfirm ?? null;
|
|
288
|
+
userOnCancel = payload.onCancel ?? null;
|
|
289
|
+
|
|
290
|
+
// 只保存用户传入的配置(过滤掉回调)
|
|
291
|
+
const { onConfirm, onCancel, ...rest } = payload;
|
|
292
|
+
tempConfig.value = rest;
|
|
293
|
+
|
|
294
|
+
// 使用内部状态控制显示
|
|
295
|
+
internalShow.value = true;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* 函数式调用关闭 modal
|
|
300
|
+
*/
|
|
301
|
+
function onServiceHide() {
|
|
302
|
+
internalShow.value = false;
|
|
303
|
+
resetTempConfig();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* 重置临时配置
|
|
308
|
+
*/
|
|
309
|
+
function resetTempConfig() {
|
|
310
|
+
tempConfig.value = {};
|
|
311
|
+
userOnConfirm = null;
|
|
312
|
+
userOnCancel = null;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
onMounted(() => {
|
|
316
|
+
if (showEvent.value) {
|
|
317
|
+
uni?.$on && uni.$on(showEvent.value, onServiceShow);
|
|
318
|
+
}
|
|
319
|
+
if (hideEvent.value) {
|
|
320
|
+
uni?.$on && uni.$on(hideEvent.value, onServiceHide);
|
|
321
|
+
}
|
|
322
|
+
if (clearLoadingEvent.value) {
|
|
323
|
+
uni?.$on && uni.$on(clearLoadingEvent.value, clearLoading);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
onBeforeUnmount(() => {
|
|
328
|
+
if (showEvent.value) {
|
|
329
|
+
uni?.$off && uni.$off(showEvent.value, onServiceShow);
|
|
330
|
+
}
|
|
331
|
+
if (hideEvent.value) {
|
|
332
|
+
uni?.$off && uni.$off(hideEvent.value, onServiceHide);
|
|
333
|
+
}
|
|
334
|
+
if (clearLoadingEvent.value) {
|
|
335
|
+
uni?.$off && uni.$off(clearLoadingEvent.value, clearLoading);
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
|
|
173
339
|
defineExpose({
|
|
174
340
|
clearLoading
|
|
175
341
|
});
|
|
@@ -13,7 +13,7 @@ export const ToastProps = {
|
|
|
13
13
|
zIndex: { type: [Number, String] as PropType<number | string>, default: zIndex.toast },
|
|
14
14
|
/** 提示类型,success/warning/error/loading 等 */
|
|
15
15
|
type: { type: String as PropType<ThemeType | 'default'>, default: '' },
|
|
16
|
-
/** 显示时长,单位ms */
|
|
16
|
+
/** 显示时长,单位ms。设为 0 表示不自动关闭,需手动调用 hide/close 方法 */
|
|
17
17
|
duration: { type: Number, default: 2000 },
|
|
18
18
|
/** 是否显示图标 */
|
|
19
19
|
icon: { type: Boolean, default: true },
|
|
@@ -31,6 +31,8 @@ export const ToastProps = {
|
|
|
31
31
|
params: { type: Object as PropType<Record<string, any>>, default: () => ({}) },
|
|
32
32
|
/** 是否作为全局根部 toast(通常放在 App.vue 中,给 useToast() 使用) */
|
|
33
33
|
global: { type: Boolean, default: false },
|
|
34
|
+
/** 是否作为页面级 toast(通常放在页面中,给 useToast({ page: true }) 使用) */
|
|
35
|
+
page: { type: Boolean, default: false },
|
|
34
36
|
/** 是否为loading “常驻” */
|
|
35
37
|
loading: { type: Boolean, default: false }
|
|
36
38
|
};
|
|
@@ -112,6 +112,7 @@ const uZIndex = computed(() => {
|
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
114
|
* 显示toast组件,由父组件通过ref.show(options)形式调用
|
|
115
|
+
* @description 当 duration 为 0 或不传时,表示不自动关闭,需要手动调用 hide/close 方法关闭
|
|
115
116
|
*/
|
|
116
117
|
function show(options: any) {
|
|
117
118
|
// 不将结果合并到config变量,避免多次调用u-toast,前后的配置造成混乱
|
|
@@ -122,15 +123,18 @@ function show(options: any) {
|
|
|
122
123
|
timer = null;
|
|
123
124
|
}
|
|
124
125
|
isShow.value = true;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
126
|
+
// duration 为 0、undefined 或小于等于 0 时,表示不自动关闭,需要手动调用 hide/close
|
|
127
|
+
if (tmpConfig.value.duration > 0) {
|
|
128
|
+
timer = setTimeout(() => {
|
|
129
|
+
// 倒计时结束,清除定时器,隐藏toast组件
|
|
130
|
+
isShow.value = false;
|
|
131
|
+
clearTimeout(timer!);
|
|
132
|
+
timer = null;
|
|
133
|
+
// 判断是否存在callback方法,如果存在就执行
|
|
134
|
+
typeof tmpConfig.value.callback === 'function' && tmpConfig.value.callback();
|
|
135
|
+
timeEnd();
|
|
136
|
+
}, tmpConfig.value.duration);
|
|
137
|
+
}
|
|
134
138
|
}
|
|
135
139
|
/**
|
|
136
140
|
* 隐藏toast组件,由父组件通过ref.hide()形式调用
|
|
@@ -194,20 +198,28 @@ function onServiceHide() {
|
|
|
194
198
|
|
|
195
199
|
// 是否为 App 根部的“全局 toast”
|
|
196
200
|
const isGlobal = computed(() => props.global);
|
|
201
|
+
// 是否为页面级 toast
|
|
202
|
+
const isPage = computed(() => props.page);
|
|
197
203
|
|
|
198
|
-
|
|
199
|
-
const
|
|
204
|
+
// 显示事件
|
|
205
|
+
const showEvent = computed(() => (isGlobal.value ? U_TOAST_GLOBAL_EVENT_SHOW : isPage.value ? U_TOAST_EVENT_SHOW : ''));
|
|
206
|
+
// 隐藏事件
|
|
207
|
+
const hideEvent = computed(() => (isGlobal.value ? U_TOAST_GLOBAL_EVENT_HIDE : isPage.value ? U_TOAST_EVENT_HIDE : ''));
|
|
200
208
|
|
|
201
209
|
onMounted(() => {
|
|
202
|
-
if (
|
|
210
|
+
if (showEvent.value) {
|
|
203
211
|
uni?.$on && uni.$on(showEvent.value, onServiceShow);
|
|
212
|
+
}
|
|
213
|
+
if (hideEvent.value) {
|
|
204
214
|
uni?.$on && uni.$on(hideEvent.value, onServiceHide);
|
|
205
215
|
}
|
|
206
216
|
});
|
|
207
217
|
|
|
208
218
|
onBeforeUnmount(() => {
|
|
209
|
-
if (
|
|
219
|
+
if (showEvent.value) {
|
|
210
220
|
uni?.$off && uni.$off(showEvent.value, onServiceShow);
|
|
221
|
+
}
|
|
222
|
+
if (hideEvent.value) {
|
|
211
223
|
uni?.$off && uni.$off(hideEvent.value, onServiceHide);
|
|
212
224
|
}
|
|
213
225
|
});
|
package/libs/hooks/index.ts
CHANGED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {
|
|
2
|
+
U_MODAL_EVENT_SHOW,
|
|
3
|
+
U_MODAL_EVENT_HIDE,
|
|
4
|
+
U_MODAL_EVENT_CLEAR_LOADING,
|
|
5
|
+
U_MODAL_GLOBAL_EVENT_SHOW,
|
|
6
|
+
U_MODAL_GLOBAL_EVENT_HIDE,
|
|
7
|
+
U_MODAL_GLOBAL_EVENT_CLEAR_LOADING,
|
|
8
|
+
type ModalPayload
|
|
9
|
+
} from '../../components/u-modal/service';
|
|
10
|
+
|
|
11
|
+
export type UseModalShowOptions = ModalPayload;
|
|
12
|
+
|
|
13
|
+
export type UseModal = {
|
|
14
|
+
/**
|
|
15
|
+
* 显示 modal
|
|
16
|
+
* - show('标题')
|
|
17
|
+
* - show({ title, content, showCancelButton, ... })
|
|
18
|
+
*/
|
|
19
|
+
show: (contentOrOptions: string | UseModalShowOptions) => void;
|
|
20
|
+
/**
|
|
21
|
+
* 显示 confirm 类型的 modal(带确认和取消按钮)
|
|
22
|
+
* - confirm('标题')
|
|
23
|
+
* - confirm({ title, content, onConfirm, onCancel })
|
|
24
|
+
*/
|
|
25
|
+
confirm: (contentOrOptions: string | UseModalShowOptions) => void;
|
|
26
|
+
/** 关闭 modal */
|
|
27
|
+
close: () => void;
|
|
28
|
+
/** 清除 loading 状态 */
|
|
29
|
+
clearLoading: () => void;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type UseModalOptions = {
|
|
33
|
+
/** 是否使用全局根部 <u-modal global /> */
|
|
34
|
+
global?: boolean;
|
|
35
|
+
/** 是否使用页面级 <u-modal page /> */
|
|
36
|
+
page?: boolean;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function normalize(contentOrOptions: string | UseModalShowOptions): UseModalShowOptions {
|
|
40
|
+
if (typeof contentOrOptions === 'string') {
|
|
41
|
+
// 如果是简单的字符串,可能是标题或内容
|
|
42
|
+
return { content: contentOrOptions };
|
|
43
|
+
}
|
|
44
|
+
return contentOrOptions || {};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Modal 函数式调用
|
|
49
|
+
* @description 需要页面/应用中至少存在一个 <u-modal global /> 或 <u-modal page /> 实例用于承接事件;不影响原调用方式。
|
|
50
|
+
* 支持两种调用方式:应用级 useModal() / useModal({ global: true }) 页面级 useModal({ page: true }) / useModal(false)
|
|
51
|
+
*/
|
|
52
|
+
export function useModal(optionsOrGlobal: UseModalOptions | boolean = true): UseModal {
|
|
53
|
+
const isGlobal = typeof optionsOrGlobal === 'boolean' ? optionsOrGlobal !== false : optionsOrGlobal.global === true;
|
|
54
|
+
const isPage = typeof optionsOrGlobal === 'boolean' ? optionsOrGlobal === false : optionsOrGlobal.page === true;
|
|
55
|
+
|
|
56
|
+
const showEvent = isGlobal ? U_MODAL_GLOBAL_EVENT_SHOW : isPage ? U_MODAL_EVENT_SHOW : '';
|
|
57
|
+
const hideEvent = isGlobal ? U_MODAL_GLOBAL_EVENT_HIDE : isPage ? U_MODAL_EVENT_HIDE : '';
|
|
58
|
+
const clearLoadingEvent = isGlobal ? U_MODAL_GLOBAL_EVENT_CLEAR_LOADING : isPage ? U_MODAL_EVENT_CLEAR_LOADING : '';
|
|
59
|
+
|
|
60
|
+
function emitShow(payload: UseModalShowOptions) {
|
|
61
|
+
if (showEvent) {
|
|
62
|
+
uni?.$emit && uni.$emit(showEvent, payload);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function emitHide() {
|
|
67
|
+
if (hideEvent) {
|
|
68
|
+
uni?.$emit && uni.$emit(hideEvent);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function emitClearLoading() {
|
|
73
|
+
if (clearLoadingEvent) {
|
|
74
|
+
uni?.$emit && uni.$emit(clearLoadingEvent);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function show(contentOrOptions: string | UseModalShowOptions) {
|
|
79
|
+
emitShow(normalize(contentOrOptions));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function confirm(contentOrOptions: string | UseModalShowOptions) {
|
|
83
|
+
const options = normalize(contentOrOptions);
|
|
84
|
+
emitShow({
|
|
85
|
+
...options,
|
|
86
|
+
showCancelButton: options.showCancelButton ?? true,
|
|
87
|
+
showConfirmButton: options.showConfirmButton ?? true
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function clearLoading() {
|
|
92
|
+
emitClearLoading();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function close() {
|
|
96
|
+
emitHide();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
show,
|
|
101
|
+
confirm,
|
|
102
|
+
close,
|
|
103
|
+
clearLoading
|
|
104
|
+
};
|
|
105
|
+
}
|
package/libs/hooks/useToast.ts
CHANGED
|
@@ -33,6 +33,8 @@ export type UseToast = {
|
|
|
33
33
|
export type UseToastOptions = {
|
|
34
34
|
/** 是否使用全局根部 <u-toast global />,默认 true;为 false 时走页面级 <u-toast /> */
|
|
35
35
|
global?: boolean;
|
|
36
|
+
/** 是否使用页面级 <u-toast page /> */
|
|
37
|
+
page?: boolean;
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
function normalize(titleOrOptions: string | UseToastShowOptions): UseToastShowOptions {
|
|
@@ -42,24 +44,25 @@ function normalize(titleOrOptions: string | UseToastShowOptions): UseToastShowOp
|
|
|
42
44
|
|
|
43
45
|
/**
|
|
44
46
|
* Toast 函数式调用
|
|
45
|
-
* @description 需要页面/应用中至少存在一个 <u-toast /> 实例用于承接事件;不影响原 ref 调用方式。
|
|
46
|
-
*
|
|
47
|
+
* @description 需要页面/应用中至少存在一个 <u-toast global /> 或 <u-toast page /> 实例用于承接事件;不影响原 ref 调用方式。
|
|
48
|
+
* 支持两种调用方式:应用级 useToast() / useToast({ global: true }) 页面级 useToast({ page: true }) / useToast(false)
|
|
47
49
|
*/
|
|
48
|
-
export function useToast(): UseToast
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const isGlobal
|
|
53
|
-
typeof optionsOrGlobal === 'boolean' ? optionsOrGlobal !== false : optionsOrGlobal.global !== false;
|
|
54
|
-
const showEvent = isGlobal ? U_TOAST_GLOBAL_EVENT_SHOW : U_TOAST_EVENT_SHOW;
|
|
55
|
-
const hideEvent = isGlobal ? U_TOAST_GLOBAL_EVENT_HIDE : U_TOAST_EVENT_HIDE;
|
|
50
|
+
export function useToast(optionsOrGlobal: UseToastOptions | boolean = true): UseToast {
|
|
51
|
+
const isGlobal = typeof optionsOrGlobal === 'boolean' ? optionsOrGlobal !== false : optionsOrGlobal.global === true;
|
|
52
|
+
const isPage = typeof optionsOrGlobal === 'boolean' ? optionsOrGlobal === false : optionsOrGlobal.page === true;
|
|
53
|
+
const showEvent = isGlobal ? U_TOAST_GLOBAL_EVENT_SHOW : isPage ? U_TOAST_EVENT_SHOW : '';
|
|
54
|
+
const hideEvent = isGlobal ? U_TOAST_GLOBAL_EVENT_HIDE : isPage ? U_TOAST_EVENT_HIDE : '';
|
|
56
55
|
|
|
57
56
|
function emitShow(payload: UseToastShowOptions) {
|
|
58
|
-
|
|
57
|
+
if (showEvent) {
|
|
58
|
+
uni?.$emit && uni.$emit(showEvent, payload);
|
|
59
|
+
}
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
function emitHide() {
|
|
62
|
-
|
|
63
|
+
if (hideEvent) {
|
|
64
|
+
uni?.$emit && uni.$emit(hideEvent);
|
|
65
|
+
}
|
|
63
66
|
}
|
|
64
67
|
function show(titleOrOptions: string | UseToastShowOptions) {
|
|
65
68
|
emitShow(normalize(titleOrOptions));
|
|
@@ -84,7 +87,7 @@ export function useToast(optionsOrGlobal: UseToastOptions | boolean = {}): UseTo
|
|
|
84
87
|
loading: (v: any) => {
|
|
85
88
|
const options = normalize(v);
|
|
86
89
|
// loading 通常需要常驻,除非用户显式传 duration
|
|
87
|
-
emitShow({ ...options, loading: true, duration: options.duration ??
|
|
90
|
+
emitShow({ ...options, loading: true, duration: options.duration ?? 0 });
|
|
88
91
|
}
|
|
89
92
|
};
|
|
90
93
|
}
|
package/locale/lang/en-US.ts
CHANGED
package/locale/lang/zh-CN.ts
CHANGED
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.5.
|
|
5
|
+
"version": "0.5.5",
|
|
6
6
|
"description": "uView Pro是基于Vue3+TS的多平台UI框架,提供80+高质量组件、便捷工具和常用模板,支持多主题、暗黑模式、多语言,支持H5/APP/鸿蒙/小程序多端开发。已在鸿蒙应用商店上架,欢迎体验!",
|
|
7
7
|
"main": "index.ts",
|
|
8
8
|
"module": "index.ts",
|