uview-pro 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +68 -24
- package/components/u-action-sheet/types.ts +1 -1
- package/components/u-alert-tips/u-alert-tips.vue +15 -15
- package/components/u-calendar/types.ts +3 -3
- package/components/u-calendar/u-calendar.vue +11 -11
- package/components/u-checkbox/types.ts +5 -1
- package/components/u-checkbox/u-checkbox.vue +41 -18
- package/components/u-checkbox-group/types.ts +2 -0
- package/components/u-checkbox-group/u-checkbox-group.vue +56 -15
- package/components/u-count-down/u-count-down.vue +4 -4
- package/components/u-empty/u-empty.vue +14 -14
- package/components/u-field/u-field.vue +18 -2
- package/components/u-form/u-form.vue +1 -1
- package/components/u-form-item/u-form-item.vue +12 -5
- package/components/u-full-screen/u-full-screen.vue +2 -2
- package/components/u-gap/u-gap.vue +3 -3
- package/components/u-input/types.ts +1 -1
- package/components/u-keyboard/types.ts +2 -2
- package/components/u-keyboard/u-keyboard.vue +3 -3
- package/components/u-link/types.ts +1 -1
- package/components/u-loadmore/types.ts +3 -3
- package/components/u-modal/types.ts +4 -4
- package/components/u-navbar/u-navbar.vue +8 -2
- package/components/u-no-network/types.ts +1 -1
- package/components/u-no-network/u-no-network.vue +5 -5
- package/components/u-pagination/types.ts +2 -2
- package/components/u-picker/types.ts +2 -2
- package/components/u-radio/types.ts +2 -0
- package/components/u-radio/u-radio.vue +16 -7
- package/components/u-radio-group/u-radio-group.vue +1 -1
- package/components/u-read-more/types.ts +2 -2
- package/components/u-search/types.ts +5 -3
- package/components/u-search/u-search.vue +1 -0
- package/components/u-section/types.ts +1 -1
- package/components/u-select/types.ts +2 -2
- package/components/u-tabbar/u-tabbar.vue +1 -1
- package/components/u-text/u-text.vue +7 -2
- package/components/u-toast/u-toast.vue +14 -11
- package/components/u-transition/types.ts +35 -0
- package/components/u-transition/u-transition.vue +437 -0
- package/components/u-upload/types.ts +1 -1
- package/components/u-upload/u-upload.vue +12 -12
- package/components/u-verification-code/types.ts +3 -3
- package/index.ts +2 -0
- package/libs/hooks/index.ts +2 -0
- package/libs/hooks/useDebounce.ts +15 -0
- package/libs/hooks/useThrottle.ts +16 -0
- package/locale/lang/en-US.ts +19 -19
- package/locale/lang/zh-CN.ts +19 -19
- package/package.json +9 -9
- package/types/components.d.ts +1 -0
- package/types/global.d.ts +14 -0
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view
|
|
3
|
+
v-if="rendered"
|
|
4
|
+
ref="rootRef"
|
|
5
|
+
class="u-transition"
|
|
6
|
+
:class="[customClass, animationClass]"
|
|
7
|
+
:style="$u.toStyle(animationStyle, customStyle)"
|
|
8
|
+
@animationstart="handleAnimationStart"
|
|
9
|
+
@animationend="handleAnimationEnd"
|
|
10
|
+
>
|
|
11
|
+
<slot />
|
|
12
|
+
</view>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script lang="ts">
|
|
16
|
+
export default {
|
|
17
|
+
name: 'u-transition',
|
|
18
|
+
options: {
|
|
19
|
+
addGlobalClass: true,
|
|
20
|
+
// #ifndef MP-TOUTIAO
|
|
21
|
+
virtualHost: true,
|
|
22
|
+
// #endif
|
|
23
|
+
styleIsolation: 'shared'
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<script setup lang="ts">
|
|
29
|
+
import { computed, nextTick, ref, watch } from 'vue';
|
|
30
|
+
import { TransitionProps } from './types';
|
|
31
|
+
import { $u } from '../..';
|
|
32
|
+
import type { TransitionDuration } from '../../types/global';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* transition 过渡动画
|
|
36
|
+
* @description 统一的过渡与进出场动效封装,支持多种预设动画和自定义时长。
|
|
37
|
+
* @tutorial https://uviewpro.cn/zh/components/transition.html
|
|
38
|
+
* @property {Boolean} show 是否展示内容(默认true)
|
|
39
|
+
* @property {String} name 预设动画名,可选 fade/slide-up/slide-down/slide-left/slide-right/zoom-in/zoom-out(默认fade)
|
|
40
|
+
* @property {String} mode 进入/离开过渡模式,等同于原生 transition 的 mode(默认空)
|
|
41
|
+
* @property {Number|Object} duration 进入/离开动画时长,单位ms,支持 { enter, leave }(默认300)
|
|
42
|
+
* @property {String} timing-function 动画曲线(默认cubic-bezier(0.2,0.8,0.2,1))
|
|
43
|
+
* @property {Number} delay 动画延迟,单位ms(默认0)
|
|
44
|
+
* @property {Boolean} appear 首次渲染时是否执行动画(默认false)
|
|
45
|
+
* @property {String} custom-class 自定义 class
|
|
46
|
+
* @property {String|Object} custom-style 自定义样式
|
|
47
|
+
* @example <u-transition :show="visible" name="slide-up"><view>content</view></u-transition>
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
const props = defineProps(TransitionProps);
|
|
51
|
+
|
|
52
|
+
const emit = defineEmits([
|
|
53
|
+
'before-enter',
|
|
54
|
+
'enter',
|
|
55
|
+
'after-enter',
|
|
56
|
+
'enter-cancelled',
|
|
57
|
+
'before-leave',
|
|
58
|
+
'leave',
|
|
59
|
+
'after-leave',
|
|
60
|
+
'leave-cancelled'
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
const normalizeDuration = (duration: number | TransitionDuration) => {
|
|
64
|
+
if (typeof duration === 'number') {
|
|
65
|
+
return {
|
|
66
|
+
enter: duration,
|
|
67
|
+
leave: duration
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
enter: duration?.enter ?? 300,
|
|
72
|
+
leave: duration?.leave ?? duration?.enter ?? 300
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const rootRef = ref();
|
|
77
|
+
const rendered = ref<boolean>(props.show);
|
|
78
|
+
const animationPhase = ref<'enter' | 'leave' | ''>('');
|
|
79
|
+
const animating = ref(false);
|
|
80
|
+
const initialized = ref(false);
|
|
81
|
+
|
|
82
|
+
const transitionDuration = computed(() => normalizeDuration(props.duration));
|
|
83
|
+
|
|
84
|
+
const animationStyle = computed(() => {
|
|
85
|
+
const currentDuration =
|
|
86
|
+
animationPhase.value === 'leave' ? transitionDuration.value.leave : transitionDuration.value.enter;
|
|
87
|
+
return {
|
|
88
|
+
'--u-transition-duration-enter': `${transitionDuration.value.enter}ms`,
|
|
89
|
+
'--u-transition-duration-leave': `${transitionDuration.value.leave}ms`,
|
|
90
|
+
'--u-transition-delay': `${props.delay}ms`,
|
|
91
|
+
'--u-transition-timing': props.timingFunction,
|
|
92
|
+
animationDuration: `${currentDuration}ms`,
|
|
93
|
+
animationDelay: `${props.delay}ms`,
|
|
94
|
+
animationTimingFunction: props.timingFunction
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const animationClass = computed(() => {
|
|
99
|
+
if (!animationPhase.value) {
|
|
100
|
+
return '';
|
|
101
|
+
}
|
|
102
|
+
return `u-transition-${props.name}-${animationPhase.value}`;
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const getEl = () => rootRef.value as any;
|
|
106
|
+
|
|
107
|
+
const startEnter = () => {
|
|
108
|
+
if (animating.value && animationPhase.value === 'enter') {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (animating.value && animationPhase.value === 'leave') {
|
|
112
|
+
emit('leave-cancelled', getEl());
|
|
113
|
+
}
|
|
114
|
+
rendered.value = true;
|
|
115
|
+
animationPhase.value = 'enter';
|
|
116
|
+
animating.value = true;
|
|
117
|
+
emit('before-enter', getEl());
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const startLeave = () => {
|
|
121
|
+
if (!rendered.value) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (animating.value && animationPhase.value === 'leave') {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (animating.value && animationPhase.value === 'enter') {
|
|
128
|
+
emit('enter-cancelled', getEl());
|
|
129
|
+
}
|
|
130
|
+
animationPhase.value = 'leave';
|
|
131
|
+
animating.value = true;
|
|
132
|
+
emit('before-leave', getEl());
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const handleAnimationStart = () => {
|
|
136
|
+
if (animationPhase.value === 'enter') {
|
|
137
|
+
emit('enter', getEl());
|
|
138
|
+
} else if (animationPhase.value === 'leave') {
|
|
139
|
+
emit('leave', getEl());
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const handleAnimationEnd = () => {
|
|
144
|
+
if (animationPhase.value === 'enter') {
|
|
145
|
+
animating.value = false;
|
|
146
|
+
animationPhase.value = '';
|
|
147
|
+
emit('after-enter', getEl());
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (animationPhase.value === 'leave') {
|
|
151
|
+
animating.value = false;
|
|
152
|
+
animationPhase.value = '';
|
|
153
|
+
rendered.value = false;
|
|
154
|
+
emit('after-leave', getEl());
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// 根据mode处理动画顺序(主要用于快速切换时的时序控制)
|
|
159
|
+
const shouldWaitForAnimation = (newPhase: 'enter' | 'leave') => {
|
|
160
|
+
if (!animating.value) return false;
|
|
161
|
+
|
|
162
|
+
const currentPhase = animationPhase.value;
|
|
163
|
+
|
|
164
|
+
// 如果当前正在进行相反的动画,根据mode决定是否需要等待
|
|
165
|
+
if (props.mode === 'out-in' && currentPhase === 'leave' && newPhase === 'enter') {
|
|
166
|
+
return true; // 等待离开动画完成
|
|
167
|
+
}
|
|
168
|
+
if (props.mode === 'in-out' && currentPhase === 'enter' && newPhase === 'leave') {
|
|
169
|
+
return true; // 等待进入动画完成
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return false;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
watch(
|
|
176
|
+
() => props.show,
|
|
177
|
+
value => {
|
|
178
|
+
if (!initialized.value) {
|
|
179
|
+
initialized.value = true;
|
|
180
|
+
if (value) {
|
|
181
|
+
rendered.value = true;
|
|
182
|
+
if (props.appear) {
|
|
183
|
+
nextTick(() => startEnter());
|
|
184
|
+
}
|
|
185
|
+
} else {
|
|
186
|
+
rendered.value = false;
|
|
187
|
+
}
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (value) {
|
|
191
|
+
if (shouldWaitForAnimation('enter')) {
|
|
192
|
+
// 根据mode等待当前动画完成后再开始进入动画
|
|
193
|
+
// 简单的方式:延迟到下一个tick检查
|
|
194
|
+
nextTick(() => {
|
|
195
|
+
if (!animating.value) {
|
|
196
|
+
startEnter();
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
} else {
|
|
200
|
+
startEnter();
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
if (shouldWaitForAnimation('leave')) {
|
|
204
|
+
// 根据mode等待当前动画完成后再开始离开动画
|
|
205
|
+
nextTick(() => {
|
|
206
|
+
if (!animating.value) {
|
|
207
|
+
startLeave();
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
} else {
|
|
211
|
+
startLeave();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
{ immediate: true }
|
|
216
|
+
);
|
|
217
|
+
</script>
|
|
218
|
+
|
|
219
|
+
<style lang="scss" scoped>
|
|
220
|
+
@import '../../libs/css/style.components.scss';
|
|
221
|
+
|
|
222
|
+
.u-transition {
|
|
223
|
+
// display: inline-flex;
|
|
224
|
+
// width: auto;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
@mixin animation-base {
|
|
228
|
+
animation-fill-mode: both;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.u-transition-fade-enter {
|
|
232
|
+
@include animation-base;
|
|
233
|
+
animation-name: u-transition-fade-in;
|
|
234
|
+
}
|
|
235
|
+
.u-transition-fade-leave {
|
|
236
|
+
@include animation-base;
|
|
237
|
+
animation-name: u-transition-fade-out;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.u-transition-slide-up-enter {
|
|
241
|
+
@include animation-base;
|
|
242
|
+
animation-name: u-transition-slide-up-in;
|
|
243
|
+
}
|
|
244
|
+
.u-transition-slide-up-leave {
|
|
245
|
+
@include animation-base;
|
|
246
|
+
animation-name: u-transition-slide-up-out;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.u-transition-slide-down-enter {
|
|
250
|
+
@include animation-base;
|
|
251
|
+
animation-name: u-transition-slide-down-in;
|
|
252
|
+
}
|
|
253
|
+
.u-transition-slide-down-leave {
|
|
254
|
+
@include animation-base;
|
|
255
|
+
animation-name: u-transition-slide-down-out;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.u-transition-slide-left-enter {
|
|
259
|
+
@include animation-base;
|
|
260
|
+
animation-name: u-transition-slide-left-in;
|
|
261
|
+
}
|
|
262
|
+
.u-transition-slide-left-leave {
|
|
263
|
+
@include animation-base;
|
|
264
|
+
animation-name: u-transition-slide-left-out;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.u-transition-slide-right-enter {
|
|
268
|
+
@include animation-base;
|
|
269
|
+
animation-name: u-transition-slide-right-in;
|
|
270
|
+
}
|
|
271
|
+
.u-transition-slide-right-leave {
|
|
272
|
+
@include animation-base;
|
|
273
|
+
animation-name: u-transition-slide-right-out;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.u-transition-zoom-in-enter {
|
|
277
|
+
@include animation-base;
|
|
278
|
+
animation-name: u-transition-zoom-in-in;
|
|
279
|
+
}
|
|
280
|
+
.u-transition-zoom-in-leave {
|
|
281
|
+
@include animation-base;
|
|
282
|
+
animation-name: u-transition-zoom-in-out;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.u-transition-zoom-out-enter {
|
|
286
|
+
@include animation-base;
|
|
287
|
+
animation-name: u-transition-zoom-out-in;
|
|
288
|
+
}
|
|
289
|
+
.u-transition-zoom-out-leave {
|
|
290
|
+
@include animation-base;
|
|
291
|
+
animation-name: u-transition-zoom-out-out;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
@keyframes u-transition-fade-in {
|
|
295
|
+
0% {
|
|
296
|
+
opacity: 0;
|
|
297
|
+
}
|
|
298
|
+
100% {
|
|
299
|
+
opacity: 1;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
@keyframes u-transition-fade-out {
|
|
304
|
+
0% {
|
|
305
|
+
opacity: 1;
|
|
306
|
+
}
|
|
307
|
+
100% {
|
|
308
|
+
opacity: 0;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
@keyframes u-transition-slide-up-in {
|
|
313
|
+
0% {
|
|
314
|
+
opacity: 0;
|
|
315
|
+
transform: translate3d(0, 40rpx, 0);
|
|
316
|
+
}
|
|
317
|
+
100% {
|
|
318
|
+
opacity: 1;
|
|
319
|
+
transform: translate3d(0, 0, 0);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
@keyframes u-transition-slide-up-out {
|
|
323
|
+
0% {
|
|
324
|
+
opacity: 1;
|
|
325
|
+
transform: translate3d(0, 0, 0);
|
|
326
|
+
}
|
|
327
|
+
100% {
|
|
328
|
+
opacity: 0;
|
|
329
|
+
transform: translate3d(0, 40rpx, 0);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
@keyframes u-transition-slide-down-in {
|
|
334
|
+
0% {
|
|
335
|
+
opacity: 0;
|
|
336
|
+
transform: translate3d(0, -40rpx, 0);
|
|
337
|
+
}
|
|
338
|
+
100% {
|
|
339
|
+
opacity: 1;
|
|
340
|
+
transform: translate3d(0, 0, 0);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
@keyframes u-transition-slide-down-out {
|
|
344
|
+
0% {
|
|
345
|
+
opacity: 1;
|
|
346
|
+
transform: translate3d(0, 0, 0);
|
|
347
|
+
}
|
|
348
|
+
100% {
|
|
349
|
+
opacity: 0;
|
|
350
|
+
transform: translate3d(0, -40rpx, 0);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
@keyframes u-transition-slide-left-in {
|
|
355
|
+
0% {
|
|
356
|
+
opacity: 0;
|
|
357
|
+
transform: translate3d(40rpx, 0, 0);
|
|
358
|
+
}
|
|
359
|
+
100% {
|
|
360
|
+
opacity: 1;
|
|
361
|
+
transform: translate3d(0, 0, 0);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
@keyframes u-transition-slide-left-out {
|
|
365
|
+
0% {
|
|
366
|
+
opacity: 1;
|
|
367
|
+
transform: translate3d(0, 0, 0);
|
|
368
|
+
}
|
|
369
|
+
100% {
|
|
370
|
+
opacity: 0;
|
|
371
|
+
transform: translate3d(40rpx, 0, 0);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@keyframes u-transition-slide-right-in {
|
|
376
|
+
0% {
|
|
377
|
+
opacity: 0;
|
|
378
|
+
transform: translate3d(-40rpx, 0, 0);
|
|
379
|
+
}
|
|
380
|
+
100% {
|
|
381
|
+
opacity: 1;
|
|
382
|
+
transform: translate3d(0, 0, 0);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
@keyframes u-transition-slide-right-out {
|
|
386
|
+
0% {
|
|
387
|
+
opacity: 1;
|
|
388
|
+
transform: translate3d(0, 0, 0);
|
|
389
|
+
}
|
|
390
|
+
100% {
|
|
391
|
+
opacity: 0;
|
|
392
|
+
transform: translate3d(-40rpx, 0, 0);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
@keyframes u-transition-zoom-in-in {
|
|
397
|
+
0% {
|
|
398
|
+
opacity: 0;
|
|
399
|
+
transform: scale(0.85);
|
|
400
|
+
}
|
|
401
|
+
100% {
|
|
402
|
+
opacity: 1;
|
|
403
|
+
transform: scale(1);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
@keyframes u-transition-zoom-in-out {
|
|
407
|
+
0% {
|
|
408
|
+
opacity: 1;
|
|
409
|
+
transform: scale(1);
|
|
410
|
+
}
|
|
411
|
+
100% {
|
|
412
|
+
opacity: 0;
|
|
413
|
+
transform: scale(0.85);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
@keyframes u-transition-zoom-out-in {
|
|
418
|
+
0% {
|
|
419
|
+
opacity: 0;
|
|
420
|
+
transform: scale(1.1);
|
|
421
|
+
}
|
|
422
|
+
100% {
|
|
423
|
+
opacity: 1;
|
|
424
|
+
transform: scale(1);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
@keyframes u-transition-zoom-out-out {
|
|
428
|
+
0% {
|
|
429
|
+
opacity: 1;
|
|
430
|
+
transform: scale(1);
|
|
431
|
+
}
|
|
432
|
+
100% {
|
|
433
|
+
opacity: 0;
|
|
434
|
+
transform: scale(1.1);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
</style>
|
|
@@ -34,7 +34,7 @@ export const UploadProps = {
|
|
|
34
34
|
/** 是否自定义上传按钮 */
|
|
35
35
|
customBtn: { type: Boolean, default: false },
|
|
36
36
|
/** 上传按钮文字 */
|
|
37
|
-
uploadText: { type: String, default: () => t('
|
|
37
|
+
uploadText: { type: String, default: () => t('uUpload.uploadText') },
|
|
38
38
|
/** 上传地址 */
|
|
39
39
|
action: { type: String, default: '' },
|
|
40
40
|
/** 是否禁用 */
|
|
@@ -205,11 +205,11 @@ function selectFile() {
|
|
|
205
205
|
if (!props.multiple && index >= 1) return;
|
|
206
206
|
if (val.size > Number(props.maxSize)) {
|
|
207
207
|
emit('on-oversize', val, lists.value, props.index);
|
|
208
|
-
showToast(t('
|
|
208
|
+
showToast(t('uUpload.overSize'));
|
|
209
209
|
} else {
|
|
210
210
|
if (Number(props.maxCount) <= lists.value.length) {
|
|
211
211
|
emit('on-exceed', val, lists.value, props.index);
|
|
212
|
-
showToast(t('
|
|
212
|
+
showToast(t('uUpload.overMaxCount'));
|
|
213
213
|
return;
|
|
214
214
|
}
|
|
215
215
|
lists.value.push({ url: val.path, progress: 0, error: false, file: val });
|
|
@@ -248,7 +248,7 @@ function retry(index: number) {
|
|
|
248
248
|
lists.value[index].error = false;
|
|
249
249
|
lists.value[index].response = null;
|
|
250
250
|
if (props.showTips) {
|
|
251
|
-
uni.showLoading({ title: t('
|
|
251
|
+
uni.showLoading({ title: t('uUpload.reUpload') });
|
|
252
252
|
}
|
|
253
253
|
uploadFile(index);
|
|
254
254
|
}
|
|
@@ -301,7 +301,7 @@ async function uploadFile(index = 0) {
|
|
|
301
301
|
}
|
|
302
302
|
// 检查上传地址
|
|
303
303
|
if (!props.action) {
|
|
304
|
-
showToast(t('
|
|
304
|
+
showToast(t('uUpload.noAction'), true);
|
|
305
305
|
return;
|
|
306
306
|
}
|
|
307
307
|
lists.value[index].error = false;
|
|
@@ -355,7 +355,7 @@ function uploadError(index: number, err: any) {
|
|
|
355
355
|
lists.value[index].error = true;
|
|
356
356
|
lists.value[index].response = null;
|
|
357
357
|
emit('on-error', err, index, lists.value, props.index);
|
|
358
|
-
showToast(t('
|
|
358
|
+
showToast(t('uUpload.uploadFailed'));
|
|
359
359
|
}
|
|
360
360
|
|
|
361
361
|
/**
|
|
@@ -363,8 +363,8 @@ function uploadError(index: number, err: any) {
|
|
|
363
363
|
*/
|
|
364
364
|
function deleteItem(index: number) {
|
|
365
365
|
uni.showModal({
|
|
366
|
-
title: t('
|
|
367
|
-
content: t('
|
|
366
|
+
title: t('uUpload.modalTitle'),
|
|
367
|
+
content: t('uUpload.deleteConfirm'),
|
|
368
368
|
success: async (res: any) => {
|
|
369
369
|
if (res.confirm) {
|
|
370
370
|
// 先检查是否有定义before-remove移除前钩子
|
|
@@ -385,11 +385,11 @@ function deleteItem(index: number) {
|
|
|
385
385
|
})
|
|
386
386
|
.catch(() => {
|
|
387
387
|
// 如果进入promise的reject,终止删除操作
|
|
388
|
-
showToast(t('
|
|
388
|
+
showToast(t('uUpload.terminatedRemove'));
|
|
389
389
|
});
|
|
390
390
|
} else if (beforeResponse === false) {
|
|
391
391
|
// 返回false,终止删除
|
|
392
|
-
showToast(t('
|
|
392
|
+
showToast(t('uUpload.terminatedRemove'));
|
|
393
393
|
} else {
|
|
394
394
|
// 如果返回true,执行删除操作
|
|
395
395
|
handlerDeleteItem(index);
|
|
@@ -413,7 +413,7 @@ function handlerDeleteItem(index: number) {
|
|
|
413
413
|
}
|
|
414
414
|
lists.value.splice(index, 1);
|
|
415
415
|
emit('on-remove', index, lists.value, props.index);
|
|
416
|
-
showToast(t('
|
|
416
|
+
showToast(t('uUpload.removeSuccess'));
|
|
417
417
|
}
|
|
418
418
|
|
|
419
419
|
/**
|
|
@@ -442,7 +442,7 @@ function doPreviewImage(url: string, index: number) {
|
|
|
442
442
|
emit('on-preview', url, lists.value, props.index);
|
|
443
443
|
},
|
|
444
444
|
fail: () => {
|
|
445
|
-
uni.showToast({ title: t('
|
|
445
|
+
uni.showToast({ title: t('uUpload.previewFailed'), icon: 'none' });
|
|
446
446
|
}
|
|
447
447
|
});
|
|
448
448
|
}
|
|
@@ -471,7 +471,7 @@ function checkFileExt(file: any) {
|
|
|
471
471
|
// 转为小写
|
|
472
472
|
return ext.toLowerCase() === fileExt;
|
|
473
473
|
});
|
|
474
|
-
if (!noArrowExt) showToast(t('
|
|
474
|
+
if (!noArrowExt) showToast(t('uUpload.notAllowedExt', { ext: fileExt }));
|
|
475
475
|
return noArrowExt;
|
|
476
476
|
}
|
|
477
477
|
|
|
@@ -13,11 +13,11 @@ export const VerificationCodeProps = {
|
|
|
13
13
|
/** 倒计时时长,单位秒 */
|
|
14
14
|
seconds: { type: [String, Number] as PropType<string | number>, default: 60 },
|
|
15
15
|
/** 开始时按钮文字 */
|
|
16
|
-
startText: { type: String, default: () => t('
|
|
16
|
+
startText: { type: String, default: () => t('uVerificationCode.startText') },
|
|
17
17
|
/** 倒计时进行中按钮文字,X为剩余秒数 */
|
|
18
|
-
changeText: { type: String, default: () => t('
|
|
18
|
+
changeText: { type: String, default: () => t('uVerificationCode.changeText') },
|
|
19
19
|
/** 结束时按钮文字 */
|
|
20
|
-
endText: { type: String, default: () => t('
|
|
20
|
+
endText: { type: String, default: () => t('uVerificationCode.endText') },
|
|
21
21
|
/** 是否保持倒计时不中断(如页面切换) */
|
|
22
22
|
keepRunning: { type: Boolean, default: false },
|
|
23
23
|
/** 唯一标识key,用于区分多个验证码组件 */
|
package/index.ts
CHANGED
package/libs/hooks/index.ts
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function useDebounce(delay: number = 500) {
|
|
2
|
+
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
3
|
+
// 防抖函数
|
|
4
|
+
function debounce(callback: () => void, debounceTime?: number) {
|
|
5
|
+
debounceTime = debounceTime || delay;
|
|
6
|
+
if (timeout) clearTimeout(timeout);
|
|
7
|
+
timeout = setTimeout(() => {
|
|
8
|
+
callback();
|
|
9
|
+
}, debounceTime);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
debounce
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function useThrottle(delay: number = 500) {
|
|
2
|
+
let previous: number = 0;
|
|
3
|
+
// 节流函数
|
|
4
|
+
function throttle(callback: () => void, throttleTime?: number) {
|
|
5
|
+
throttleTime = throttleTime || delay;
|
|
6
|
+
let now = Date.now();
|
|
7
|
+
if (now - previous > throttleTime) {
|
|
8
|
+
callback();
|
|
9
|
+
previous = now;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
throttle
|
|
15
|
+
};
|
|
16
|
+
}
|