hy-app 0.3.0 → 0.3.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/README.md +6 -3
- package/common/shakeService.ts +31 -29
- package/components/avatar.zip +0 -0
- package/components/hy-action-sheet/hy-action-sheet.vue +71 -46
- package/components/hy-address-picker/hy-address-picker.vue +94 -83
- package/components/hy-avatar/hy-avatar.vue +84 -85
- package/components/hy-back-top/hy-back-top.vue +8 -6
- package/components/hy-badge/hy-badge.vue +47 -46
- package/components/hy-button/hy-button.vue +117 -93
- package/components/hy-calendar/hy-calendar.vue +168 -160
- package/components/hy-card/hy-card.vue +50 -43
- package/components/hy-card/typing.d.ts +33 -32
- package/components/hy-cell/hy-cell.vue +73 -51
- package/components/hy-check-button/hy-check-button.vue +54 -47
- package/components/hy-checkbox/hy-checkbox.vue +97 -105
- package/components/hy-code-input/hy-code-input.vue +80 -89
- package/components/hy-config-provider/hy-config-provider.vue +20 -21
- package/components/hy-count-down/hy-count-down.vue +66 -67
- package/components/hy-count-to/hy-count-to.vue +105 -99
- package/components/hy-count-to/typing.d.ts +13 -12
- package/components/hy-datetime-picker/hy-datetime-picker.vue +261 -253
- package/components/hy-datetime-picker/typing.d.ts +42 -40
- package/components/hy-divider/hy-divider.vue +68 -73
- package/components/hy-dropdown/hy-dropdown.vue +20 -19
- package/components/hy-dropdown-item/hy-dropdown-item.vue +66 -61
- package/components/hy-dropdown-item/typing.d.ts +9 -9
- package/components/hy-empty/hy-empty.vue +42 -42
- package/components/hy-flex/hy-flex.vue +99 -0
- package/components/hy-flex/index.scss +8 -0
- package/components/hy-flex/typing.d.ts +23 -0
- package/components/hy-float-button/hy-float-button.vue +218 -210
- package/components/hy-folding-panel/hy-folding-panel.vue +32 -33
- package/components/hy-form/hy-form.vue +264 -252
- package/components/hy-form/typing.d.ts +4 -0
- package/components/hy-form-group/hy-form-group.vue +114 -183
- package/components/hy-form-item/hy-form-item.vue +12 -10
- package/components/hy-form-item/index.scss +2 -2
- package/components/hy-form-item/typing.d.ts +3 -6
- package/components/hy-grid/hy-grid.vue +44 -43
- package/components/hy-icon/hy-icon.vue +61 -67
- package/components/hy-image/hy-image.vue +112 -88
- package/components/hy-image/typing.d.ts +27 -23
- package/components/hy-input/hy-input.vue +157 -127
- package/components/hy-input/typing.d.ts +53 -47
- package/components/hy-line/hy-line.vue +26 -26
- package/components/hy-line-progress/hy-line-progress.vue +42 -35
- package/components/hy-list/hy-list.vue +76 -85
- package/components/hy-loading/hy-loading.vue +26 -23
- package/components/hy-login/TheUserLogin.vue +1 -1
- package/components/hy-menu/hy-menu.vue +48 -43
- package/components/hy-menu/typing.d.ts +18 -17
- package/components/hy-modal/hy-modal.vue +39 -35
- package/components/hy-navbar/hy-navbar.vue +25 -25
- package/components/hy-navbar/typing.d.ts +24 -22
- package/components/hy-notice-bar/hy-notice-bar.vue +26 -27
- package/components/hy-notify/hy-notify.vue +53 -53
- package/components/hy-number-step/hy-number-step.vue +134 -146
- package/components/hy-number-step/typing.d.ts +35 -35
- package/components/hy-overlay/hy-overlay.vue +23 -21
- package/components/hy-pagination/hy-pagination.vue +41 -36
- package/components/hy-picker/hy-picker.vue +184 -154
- package/components/hy-picker/typing.d.ts +39 -39
- package/components/hy-popover/hy-popover.vue +97 -77
- package/components/hy-popup/hy-popup.vue +107 -98
- package/components/hy-price/hy-price.vue +38 -34
- package/components/hy-qrcode/hy-qrcode.vue +50 -51
- package/components/hy-radio/hy-radio.vue +101 -113
- package/components/hy-rate/hy-rate.vue +107 -88
- package/components/hy-read-more/hy-read-more.vue +64 -49
- package/components/hy-scroll-list/hy-scroll-list.vue +45 -48
- package/components/hy-search/hy-search.vue +73 -66
- package/components/hy-search/typing.d.ts +36 -35
- package/components/hy-signature/hy-signature.vue +282 -240
- package/components/hy-slider/hy-slider.vue +195 -153
- package/components/hy-slider/typing.d.ts +21 -21
- package/components/hy-steps/hy-steps.vue +118 -90
- package/components/hy-steps/index.scss +31 -21
- package/components/hy-submit-bar/hy-submit-bar.vue +61 -70
- package/components/hy-subsection/hy-subsection.vue +99 -102
- package/components/hy-subsection/typing.d.ts +19 -19
- package/components/hy-swipe-action/hy-swipe-action.vue +131 -118
- package/components/hy-swiper/hy-swiper.vue +85 -71
- package/components/hy-switch/hy-switch.vue +67 -72
- package/components/hy-switch/typing.d.ts +21 -19
- package/components/hy-tabs/hy-tabs.vue +168 -113
- package/components/hy-tag/hy-tag.vue +90 -86
- package/components/hy-tag/typing.d.ts +26 -21
- package/components/hy-text/hy-text.vue +119 -111
- package/components/hy-textarea/hy-textarea.vue +100 -93
- package/components/hy-textarea/typing.d.ts +36 -31
- package/components/hy-toast/hy-toast.vue +77 -67
- package/components/hy-tooltip/hy-tooltip.vue +109 -91
- package/components/hy-transition/hy-transition.vue +62 -66
- package/components/hy-upload/hy-upload.vue +294 -152
- package/components/hy-upload/typing.d.ts +41 -36
- package/components/hy-warn/hy-warn.vue +34 -27
- package/components/hy-waterfall/hy-waterfall.vue +83 -74
- package/components/hy-watermark/hy-watermark.vue +134 -115
- package/components/index.ts +1 -1
- package/composables/usePopover.ts +236 -221
- package/composables/useQueue.ts +53 -52
- package/global.d.ts +1 -0
- package/package.json +2 -2
- package/store/index.ts +9 -1
- package/theme.scss +5 -5
- package/typing/index.ts +0 -1
- package/typing/modules/common.d.ts +0 -2
- package/web-types.json +1 -1
|
@@ -43,26 +43,27 @@
|
|
|
43
43
|
|
|
44
44
|
<script lang="ts">
|
|
45
45
|
export default {
|
|
46
|
-
name:
|
|
46
|
+
name: "hy-code-input",
|
|
47
47
|
options: {
|
|
48
48
|
addGlobalClass: true,
|
|
49
49
|
virtualHost: true,
|
|
50
|
-
styleIsolation:
|
|
50
|
+
styleIsolation: "shared",
|
|
51
51
|
},
|
|
52
|
-
}
|
|
52
|
+
};
|
|
53
53
|
</script>
|
|
54
54
|
|
|
55
55
|
<script setup lang="ts">
|
|
56
|
-
import { computed, nextTick, onUnmounted, ref,
|
|
57
|
-
import type { CSSProperties, PropType } from
|
|
58
|
-
import type { ICodeInputEmits } from
|
|
59
|
-
import { addUnit, getPx } from
|
|
56
|
+
import { computed, nextTick, onUnmounted, ref, watch } from "vue";
|
|
57
|
+
import type { CSSProperties, PropType } from "vue";
|
|
58
|
+
import type { ICodeInputEmits } from "./typing";
|
|
59
|
+
import { addUnit, getPx } from "../../utils";
|
|
60
|
+
import type { InputOnInputEvent } from "@uni-helper/uni-types";
|
|
60
61
|
|
|
61
62
|
/**
|
|
62
63
|
* 一般用于验证用户短信验证码的场景,也可以结合华玥的键盘组件使用
|
|
63
64
|
* @displayName hy-code-input
|
|
64
65
|
*/
|
|
65
|
-
defineOptions({})
|
|
66
|
+
defineOptions({});
|
|
66
67
|
|
|
67
68
|
// const props = withDefaults(defineProps<IProps>(), defaultProps)
|
|
68
69
|
const props = defineProps({
|
|
@@ -97,7 +98,7 @@ const props = defineProps({
|
|
|
97
98
|
* */
|
|
98
99
|
mode: {
|
|
99
100
|
type: String,
|
|
100
|
-
default:
|
|
101
|
+
default: "box",
|
|
101
102
|
},
|
|
102
103
|
/** 是否细边框 */
|
|
103
104
|
hairline: {
|
|
@@ -147,38 +148,26 @@ const props = defineProps({
|
|
|
147
148
|
customStyle: {
|
|
148
149
|
type: Object as PropType<CSSProperties>,
|
|
149
150
|
},
|
|
150
|
-
})
|
|
151
|
-
const
|
|
152
|
-
modelValue,
|
|
153
|
-
focus,
|
|
154
|
-
maxlength,
|
|
155
|
-
border,
|
|
156
|
-
disabledDot,
|
|
157
|
-
size,
|
|
158
|
-
mode,
|
|
159
|
-
hairline,
|
|
160
|
-
space,
|
|
161
|
-
borderColor,
|
|
162
|
-
} = toRefs(props)
|
|
163
|
-
const emit = defineEmits<ICodeInputEmits>()
|
|
151
|
+
});
|
|
152
|
+
const emit = defineEmits<ICodeInputEmits>();
|
|
164
153
|
|
|
165
|
-
const current = ref(0)
|
|
166
|
-
const inputValue = ref(
|
|
167
|
-
const isFocus = ref(focus
|
|
168
|
-
let timer: ReturnType<typeof setInterval
|
|
169
|
-
const opacity = ref(1)
|
|
170
|
-
const borderWidth = computed(() => (hairline
|
|
171
|
-
const lineHeight = computed(() => (hairline
|
|
172
|
-
const boxSize = addUnit(size
|
|
154
|
+
const current = ref(0);
|
|
155
|
+
const inputValue = ref("");
|
|
156
|
+
const isFocus = ref(props.focus);
|
|
157
|
+
let timer: ReturnType<typeof setInterval>;
|
|
158
|
+
const opacity = ref(1);
|
|
159
|
+
const borderWidth = computed(() => (props.hairline ? "0.5px" : "2px"));
|
|
160
|
+
const lineHeight = computed(() => (props.hairline ? "2px" : "4px"));
|
|
161
|
+
const boxSize = addUnit(props.size);
|
|
173
162
|
|
|
174
163
|
watch(
|
|
175
|
-
() => modelValue
|
|
164
|
+
() => props.modelValue,
|
|
176
165
|
(newValue: string | number) => {
|
|
177
|
-
inputValue.value = String(newValue).substring(0, maxlength
|
|
178
|
-
current.value = newValue.toString().length
|
|
166
|
+
inputValue.value = String(newValue).substring(0, props.maxlength);
|
|
167
|
+
current.value = newValue.toString().length;
|
|
179
168
|
},
|
|
180
169
|
{ immediate: true },
|
|
181
|
-
)
|
|
170
|
+
);
|
|
182
171
|
|
|
183
172
|
watch(
|
|
184
173
|
() => isFocus.value,
|
|
@@ -186,123 +175,125 @@ watch(
|
|
|
186
175
|
// #ifdef APP-NVUE
|
|
187
176
|
if (newValue) {
|
|
188
177
|
timer = setInterval(() => {
|
|
189
|
-
opacity.value = Math.abs(opacity.value - 1)
|
|
190
|
-
}, 600)
|
|
178
|
+
opacity.value = Math.abs(opacity.value - 1);
|
|
179
|
+
}, 600);
|
|
191
180
|
} else {
|
|
192
|
-
clearInterval(timer)
|
|
181
|
+
clearInterval(timer);
|
|
193
182
|
}
|
|
194
183
|
// #endif
|
|
195
184
|
},
|
|
196
|
-
)
|
|
185
|
+
);
|
|
197
186
|
|
|
198
187
|
onUnmounted(() => {
|
|
199
188
|
// #ifdef APP-NVUE
|
|
200
|
-
clearInterval(timer)
|
|
189
|
+
clearInterval(timer);
|
|
201
190
|
// #endif
|
|
202
|
-
})
|
|
191
|
+
});
|
|
203
192
|
|
|
204
193
|
// 根据长度,循环输入框的个数,因为头条小程序数值不能用于v-for
|
|
205
194
|
const codeLength = computed(() => {
|
|
206
|
-
return new Array(Number(maxlength
|
|
207
|
-
})
|
|
195
|
+
return new Array(Number(props.maxlength));
|
|
196
|
+
});
|
|
208
197
|
// 循环item的样式
|
|
209
198
|
const itemStyle = computed(() => {
|
|
210
199
|
return (index: number) => {
|
|
211
200
|
const style: CSSProperties = {
|
|
212
201
|
width: boxSize,
|
|
213
202
|
height: boxSize,
|
|
214
|
-
}
|
|
215
|
-
if (borderColor
|
|
216
|
-
style[
|
|
203
|
+
};
|
|
204
|
+
if (props.borderColor) {
|
|
205
|
+
style["--hy-border-color"] = props.borderColor;
|
|
217
206
|
}
|
|
218
207
|
// 盒子模式下,需要额外进行处理
|
|
219
|
-
if (mode
|
|
208
|
+
if (props.mode === "box" && props.border) {
|
|
220
209
|
// 设置盒子的边框,如果是细边框,则设置为1px宽度
|
|
221
|
-
style.borderWidth = borderWidth.value
|
|
222
|
-
style.borderStyle =
|
|
223
|
-
style.borderColor = borderColor
|
|
210
|
+
style.borderWidth = borderWidth.value;
|
|
211
|
+
style.borderStyle = "solid";
|
|
212
|
+
style.borderColor = props.borderColor;
|
|
224
213
|
// 如果盒子间距为0的话
|
|
225
|
-
if (getPx(space
|
|
214
|
+
if (getPx(props.space) === 0) {
|
|
226
215
|
// 给第一和最后一个盒子设置圆角
|
|
227
216
|
if (index === 0) {
|
|
228
|
-
style.borderTopLeftRadius =
|
|
229
|
-
style.borderBottomLeftRadius =
|
|
217
|
+
style.borderTopLeftRadius = "6px";
|
|
218
|
+
style.borderBottomLeftRadius = "6px";
|
|
230
219
|
}
|
|
231
220
|
if (index === codeLength.value.length - 1) {
|
|
232
|
-
style.borderTopRightRadius =
|
|
233
|
-
style.borderBottomRightRadius =
|
|
221
|
+
style.borderTopRightRadius = "6px";
|
|
222
|
+
style.borderBottomRightRadius = "6px";
|
|
234
223
|
}
|
|
235
224
|
// 最后一个盒子的右边框需要保留
|
|
236
225
|
if (index !== codeLength.value.length - 1) {
|
|
237
|
-
style.borderRight =
|
|
226
|
+
style.borderRight = "none";
|
|
238
227
|
}
|
|
239
228
|
}
|
|
240
229
|
}
|
|
241
230
|
if (index !== codeLength.value.length - 1) {
|
|
242
231
|
// 设置验证码字符之间的距离,通过margin-right设置,最后一个字符,无需右边框
|
|
243
|
-
style.marginRight = addUnit(space
|
|
232
|
+
style.marginRight = addUnit(props.space);
|
|
244
233
|
} else {
|
|
245
234
|
// 最后一个盒子的有边框需要保留
|
|
246
|
-
style.marginRight = 0
|
|
235
|
+
style.marginRight = 0;
|
|
247
236
|
}
|
|
248
237
|
|
|
249
|
-
return style
|
|
250
|
-
}
|
|
251
|
-
})
|
|
238
|
+
return style;
|
|
239
|
+
};
|
|
240
|
+
});
|
|
252
241
|
|
|
253
242
|
const itemClass = computed(() => {
|
|
254
243
|
return (index: number) => {
|
|
255
244
|
return [
|
|
256
|
-
|
|
257
|
-
border
|
|
245
|
+
"hy-code-input--item",
|
|
246
|
+
props.border
|
|
247
|
+
? `hy-code-input--item__${props.mode}`
|
|
248
|
+
: "hy-code-input--item__not",
|
|
258
249
|
current.value > index &&
|
|
259
|
-
getPx(space
|
|
260
|
-
border
|
|
261
|
-
`hy-code-input--item__${mode
|
|
250
|
+
getPx(props.space) != 0 &&
|
|
251
|
+
props.border &&
|
|
252
|
+
`hy-code-input--item__${props.mode}__border`,
|
|
262
253
|
isFocus.value &&
|
|
263
254
|
current.value === index &&
|
|
264
|
-
getPx(space
|
|
265
|
-
(border
|
|
266
|
-
? `hy-code-input--item__${mode
|
|
267
|
-
:
|
|
268
|
-
]
|
|
269
|
-
}
|
|
270
|
-
})
|
|
255
|
+
getPx(props.space) != 0 &&
|
|
256
|
+
(props.border
|
|
257
|
+
? `hy-code-input--item__${props.mode}__active`
|
|
258
|
+
: "hy-code-input--item__not__active"),
|
|
259
|
+
];
|
|
260
|
+
};
|
|
261
|
+
});
|
|
271
262
|
|
|
272
263
|
/**
|
|
273
264
|
* @description 将输入的值,转为数组,给item历遍时,根据当前的索引显示数组的元素
|
|
274
265
|
*/
|
|
275
266
|
const codeArray = computed(() => {
|
|
276
|
-
return String(inputValue.value).split(
|
|
277
|
-
})
|
|
267
|
+
return String(inputValue.value).split("");
|
|
268
|
+
});
|
|
278
269
|
|
|
279
270
|
/**
|
|
280
271
|
* @description 监听输入框的值发生变化
|
|
281
272
|
* */
|
|
282
|
-
const inputHandler = (e:
|
|
283
|
-
const value = e.detail.value
|
|
284
|
-
inputValue.value = value
|
|
273
|
+
const inputHandler = (e: InputOnInputEvent) => {
|
|
274
|
+
const value = e.detail.value;
|
|
275
|
+
inputValue.value = value;
|
|
285
276
|
// 是否允许输入“.”符号
|
|
286
|
-
if (disabledDot
|
|
277
|
+
if (props.disabledDot) {
|
|
287
278
|
nextTick(() => {
|
|
288
|
-
inputValue.value = value.replace(
|
|
289
|
-
})
|
|
279
|
+
inputValue.value = value.replace(".", "");
|
|
280
|
+
});
|
|
290
281
|
}
|
|
291
282
|
// 未达到maxlength之前,发送change事件,达到后发送finish事件
|
|
292
|
-
emit(
|
|
283
|
+
emit("change", value);
|
|
293
284
|
// 修改通过v-model双向绑定的值
|
|
294
|
-
emit(
|
|
285
|
+
emit("update:modelValue", value);
|
|
295
286
|
// 达到用户指定输入长度时,发出完成事件
|
|
296
|
-
if (String(value).length >= Number(maxlength
|
|
297
|
-
emit(
|
|
287
|
+
if (String(value).length >= Number(props.maxlength)) {
|
|
288
|
+
emit("finish", value);
|
|
298
289
|
}
|
|
299
|
-
}
|
|
290
|
+
};
|
|
300
291
|
</script>
|
|
301
292
|
|
|
302
293
|
<style scoped lang="scss">
|
|
303
|
-
@import
|
|
304
|
-
@import
|
|
305
|
-
@import
|
|
294
|
+
@import "./index.scss";
|
|
295
|
+
@import "../../libs/css/mixin.scss";
|
|
296
|
+
@import "../../theme.scss";
|
|
306
297
|
@include b(code-input) {
|
|
307
298
|
@include m(item) {
|
|
308
299
|
&__box {
|
|
@@ -7,26 +7,26 @@
|
|
|
7
7
|
|
|
8
8
|
<script lang="ts">
|
|
9
9
|
export default {
|
|
10
|
-
name:
|
|
10
|
+
name: "hy-config-provider",
|
|
11
11
|
options: {
|
|
12
12
|
addGlobalClass: true,
|
|
13
13
|
virtualHost: true,
|
|
14
|
-
styleIsolation:
|
|
14
|
+
styleIsolation: "shared",
|
|
15
15
|
},
|
|
16
|
-
}
|
|
16
|
+
};
|
|
17
17
|
</script>
|
|
18
18
|
|
|
19
19
|
<script setup lang="ts">
|
|
20
|
-
import { computed
|
|
21
|
-
import type { CSSProperties, PropType } from
|
|
22
|
-
import { addUnit, colorGradient } from
|
|
23
|
-
import { ColorConfig } from
|
|
20
|
+
import { computed } from "vue";
|
|
21
|
+
import type { CSSProperties, PropType } from "vue";
|
|
22
|
+
import { addUnit, colorGradient } from "../../utils";
|
|
23
|
+
import { ColorConfig } from "../../config";
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* 将 ConfigProvider 组件的 theme 属性设置为 dark,可以开启深色模式。 深色模式会全局生效,使页面上的所有 Wot 组件变为深色风格。
|
|
27
27
|
* @displayName hy-config-provider
|
|
28
28
|
*/
|
|
29
|
-
defineOptions({})
|
|
29
|
+
defineOptions({});
|
|
30
30
|
|
|
31
31
|
// const props = withDefaults(defineProps<IProps>(), defaultProps);
|
|
32
32
|
const props = defineProps({
|
|
@@ -36,7 +36,7 @@ const props = defineProps({
|
|
|
36
36
|
* */
|
|
37
37
|
theme: {
|
|
38
38
|
type: String,
|
|
39
|
-
default:
|
|
39
|
+
default: "light",
|
|
40
40
|
},
|
|
41
41
|
/** 主题色 */
|
|
42
42
|
themeColor: {
|
|
@@ -49,27 +49,26 @@ const props = defineProps({
|
|
|
49
49
|
customClass: String,
|
|
50
50
|
/** 定义需要用到的外部样式 */
|
|
51
51
|
customStyle: {
|
|
52
|
-
type: Object as PropType<CSSProperties>,
|
|
52
|
+
type: [Object, Array] as PropType<CSSProperties | CSSProperties[]>,
|
|
53
53
|
},
|
|
54
|
-
})
|
|
55
|
-
const { theme, themeColor, customClass, customStyle, padding } = toRefs(props)
|
|
54
|
+
});
|
|
56
55
|
|
|
57
56
|
const themeClass = computed(() => {
|
|
58
|
-
return [customClass
|
|
59
|
-
})
|
|
57
|
+
return [props.customClass, "hy-config-provider", `hy-theme--${props.theme}`];
|
|
58
|
+
});
|
|
60
59
|
|
|
61
60
|
const themeStyle = computed(() => {
|
|
62
61
|
return [
|
|
63
62
|
{
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
padding: addUnit(padding
|
|
63
|
+
"--hy-theme-color": props.themeColor,
|
|
64
|
+
"--hy-theme--light": colorGradient(props.themeColor)[90],
|
|
65
|
+
padding: addUnit(props.padding),
|
|
67
66
|
},
|
|
68
|
-
customStyle
|
|
69
|
-
]
|
|
70
|
-
})
|
|
67
|
+
props.customStyle,
|
|
68
|
+
];
|
|
69
|
+
});
|
|
71
70
|
</script>
|
|
72
71
|
|
|
73
72
|
<style scoped lang="scss">
|
|
74
|
-
@import
|
|
73
|
+
@import "./index.scss";
|
|
75
74
|
</style>
|
|
@@ -12,26 +12,26 @@
|
|
|
12
12
|
|
|
13
13
|
<script lang="ts">
|
|
14
14
|
export default {
|
|
15
|
-
name:
|
|
15
|
+
name: "hy-count-down",
|
|
16
16
|
options: {
|
|
17
17
|
addGlobalClass: true,
|
|
18
18
|
virtualHost: true,
|
|
19
|
-
styleIsolation:
|
|
19
|
+
styleIsolation: "shared",
|
|
20
20
|
},
|
|
21
|
-
}
|
|
21
|
+
};
|
|
22
22
|
</script>
|
|
23
23
|
|
|
24
24
|
<script setup lang="ts">
|
|
25
|
-
import { onMounted, onUnmounted, ref,
|
|
26
|
-
import type { CSSProperties, PropType } from
|
|
27
|
-
import { isSameSecond, parseFormat, parseTimeData } from
|
|
28
|
-
import type { ICountDownEmits } from
|
|
25
|
+
import { onMounted, onUnmounted, ref, watch } from "vue";
|
|
26
|
+
import type { CSSProperties, PropType } from "vue";
|
|
27
|
+
import { isSameSecond, parseFormat, parseTimeData } from "./index";
|
|
28
|
+
import type { ICountDownEmits } from "./typing";
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* 一般使用于某个活动的截止时间上,通过数字的变化,给用户明确的时间感受,提示用户进行某一个行为操作。
|
|
32
32
|
* @displayName hy-count-down
|
|
33
33
|
*/
|
|
34
|
-
defineOptions({})
|
|
34
|
+
defineOptions({});
|
|
35
35
|
|
|
36
36
|
// const props = withDefaults(defineProps<IProps>(), defaultProps)
|
|
37
37
|
const props = defineProps({
|
|
@@ -43,7 +43,7 @@ const props = defineProps({
|
|
|
43
43
|
/** 时间格式,DD-日,HH-时,mm-分,ss-秒,SSS-毫秒 */
|
|
44
44
|
format: {
|
|
45
45
|
type: String,
|
|
46
|
-
default:
|
|
46
|
+
default: "HH:mm:ss",
|
|
47
47
|
},
|
|
48
48
|
/** 是否自动开始倒计时 */
|
|
49
49
|
autoStart: {
|
|
@@ -61,139 +61,138 @@ const props = defineProps({
|
|
|
61
61
|
},
|
|
62
62
|
/** 自定义外部类名 */
|
|
63
63
|
customClass: String,
|
|
64
|
-
})
|
|
65
|
-
const
|
|
66
|
-
const emit = defineEmits<ICountDownEmits>()
|
|
64
|
+
});
|
|
65
|
+
const emit = defineEmits<ICountDownEmits>();
|
|
67
66
|
|
|
68
|
-
let timer: any
|
|
67
|
+
let timer: any;
|
|
69
68
|
// 各单位(天,时,分等)剩余时间
|
|
70
|
-
const timeData = ref(parseTimeData(time
|
|
69
|
+
const timeData = ref(parseTimeData(props.time));
|
|
71
70
|
// 格式化后的时间,如"03:23:21"
|
|
72
|
-
const formattedTime = ref(
|
|
71
|
+
const formattedTime = ref("");
|
|
73
72
|
// 倒计时是否正在进行中
|
|
74
|
-
const runing = ref(false)
|
|
73
|
+
const runing = ref(false);
|
|
75
74
|
// 结束的毫秒时间戳
|
|
76
|
-
const endTime = ref(0)
|
|
75
|
+
const endTime = ref(0);
|
|
77
76
|
// 剩余的毫秒时间
|
|
78
|
-
const remainTime = ref(0)
|
|
77
|
+
const remainTime = ref(0);
|
|
79
78
|
|
|
80
79
|
watch(
|
|
81
|
-
() => time
|
|
80
|
+
() => props.time,
|
|
82
81
|
() => reset(),
|
|
83
|
-
)
|
|
82
|
+
);
|
|
84
83
|
|
|
85
84
|
onMounted(() => {
|
|
86
|
-
reset()
|
|
87
|
-
})
|
|
85
|
+
reset();
|
|
86
|
+
});
|
|
88
87
|
|
|
89
88
|
onUnmounted(() => {
|
|
90
|
-
clearTimeoutFn()
|
|
91
|
-
})
|
|
89
|
+
clearTimeoutFn();
|
|
90
|
+
});
|
|
92
91
|
|
|
93
92
|
/**
|
|
94
93
|
* @description 开始倒计时
|
|
95
94
|
*/
|
|
96
95
|
const start = () => {
|
|
97
|
-
if (runing.value) return
|
|
96
|
+
if (runing.value) return;
|
|
98
97
|
// 标识为进行中
|
|
99
|
-
runing.value = true
|
|
98
|
+
runing.value = true;
|
|
100
99
|
// 结束时间戳 = 此刻时间戳 + 剩余的时间
|
|
101
|
-
endTime.value = Date.now() + remainTime.value
|
|
102
|
-
toTick()
|
|
103
|
-
}
|
|
100
|
+
endTime.value = Date.now() + remainTime.value;
|
|
101
|
+
toTick();
|
|
102
|
+
};
|
|
104
103
|
|
|
105
104
|
/**
|
|
106
105
|
* @description 根据是否展示毫秒,执行不同操作函数
|
|
107
106
|
*/
|
|
108
107
|
const toTick = () => {
|
|
109
|
-
if (millisecond
|
|
110
|
-
microTick()
|
|
108
|
+
if (props.millisecond) {
|
|
109
|
+
microTick();
|
|
111
110
|
} else {
|
|
112
|
-
macroTick()
|
|
111
|
+
macroTick();
|
|
113
112
|
}
|
|
114
|
-
}
|
|
113
|
+
};
|
|
115
114
|
const macroTick = () => {
|
|
116
|
-
clearTimeoutFn()
|
|
115
|
+
clearTimeoutFn();
|
|
117
116
|
// 每隔一定时间,更新一遍定时器的值
|
|
118
117
|
// 同时此定时器的作用也能带来毫秒级的更新
|
|
119
118
|
timer = setTimeout(() => {
|
|
120
119
|
// 获取剩余时间
|
|
121
|
-
const remain = getRemainTime()
|
|
120
|
+
const remain = getRemainTime();
|
|
122
121
|
// 重设剩余时间
|
|
123
122
|
if (!isSameSecond(remain, remainTime.value) || remain === 0) {
|
|
124
|
-
setRemainTime(remain)
|
|
123
|
+
setRemainTime(remain);
|
|
125
124
|
}
|
|
126
125
|
// 如果剩余时间不为0,则继续检查更新倒计时
|
|
127
126
|
if (remainTime.value !== 0) {
|
|
128
|
-
macroTick()
|
|
127
|
+
macroTick();
|
|
129
128
|
}
|
|
130
|
-
}, 30)
|
|
131
|
-
}
|
|
129
|
+
}, 30);
|
|
130
|
+
};
|
|
132
131
|
|
|
133
132
|
const microTick = () => {
|
|
134
|
-
clearTimeoutFn()
|
|
133
|
+
clearTimeoutFn();
|
|
135
134
|
timer = setTimeout(() => {
|
|
136
|
-
setRemainTime(getRemainTime())
|
|
135
|
+
setRemainTime(getRemainTime());
|
|
137
136
|
if (remainTime.value !== 0) {
|
|
138
|
-
microTick()
|
|
137
|
+
microTick();
|
|
139
138
|
}
|
|
140
|
-
}, 50)
|
|
141
|
-
}
|
|
139
|
+
}, 50);
|
|
140
|
+
};
|
|
142
141
|
|
|
143
142
|
/**
|
|
144
143
|
* @description 获取剩余的时间
|
|
145
144
|
*/
|
|
146
145
|
const getRemainTime = () => {
|
|
147
146
|
// 取最大值,防止出现小于0的剩余时间值
|
|
148
|
-
return Math.max(endTime.value - Date.now(), 0)
|
|
149
|
-
}
|
|
147
|
+
return Math.max(endTime.value - Date.now(), 0);
|
|
148
|
+
};
|
|
150
149
|
/**
|
|
151
150
|
* @description 设置剩余的时间
|
|
152
151
|
*/
|
|
153
152
|
const setRemainTime = (remain: number) => {
|
|
154
|
-
remainTime.value = remain
|
|
153
|
+
remainTime.value = remain;
|
|
155
154
|
// 根据剩余的毫秒时间,得出该有天,小时,分钟等的值,返回一个对象
|
|
156
|
-
timeData.value = parseTimeData(remain)
|
|
157
|
-
emit(
|
|
155
|
+
timeData.value = parseTimeData(remain);
|
|
156
|
+
emit("change", timeData.value);
|
|
158
157
|
// 得出格式化后的时间
|
|
159
|
-
formattedTime.value = parseFormat(format
|
|
158
|
+
formattedTime.value = parseFormat(props.format, timeData.value);
|
|
160
159
|
// 如果时间已到,停止倒计时
|
|
161
160
|
if (remain <= 0) {
|
|
162
|
-
pause()
|
|
163
|
-
emit(
|
|
161
|
+
pause();
|
|
162
|
+
emit("finish");
|
|
164
163
|
}
|
|
165
|
-
}
|
|
164
|
+
};
|
|
166
165
|
// 重置倒计时
|
|
167
166
|
const reset = () => {
|
|
168
|
-
pause()
|
|
169
|
-
remainTime.value = time
|
|
170
|
-
setRemainTime(remainTime.value)
|
|
171
|
-
if (autoStart
|
|
172
|
-
start()
|
|
167
|
+
pause();
|
|
168
|
+
remainTime.value = props.time;
|
|
169
|
+
setRemainTime(remainTime.value);
|
|
170
|
+
if (props.autoStart) {
|
|
171
|
+
start();
|
|
173
172
|
}
|
|
174
|
-
}
|
|
173
|
+
};
|
|
175
174
|
/**
|
|
176
175
|
* @description 暂停倒计时
|
|
177
176
|
* */
|
|
178
177
|
const pause = () => {
|
|
179
|
-
runing.value = false
|
|
180
|
-
clearTimeoutFn()
|
|
181
|
-
}
|
|
178
|
+
runing.value = false;
|
|
179
|
+
clearTimeoutFn();
|
|
180
|
+
};
|
|
182
181
|
/**
|
|
183
182
|
* @description 清空定时器
|
|
184
183
|
* */
|
|
185
184
|
const clearTimeoutFn = () => {
|
|
186
|
-
clearTimeout(timer)
|
|
187
|
-
timer = null
|
|
188
|
-
}
|
|
185
|
+
clearTimeout(timer);
|
|
186
|
+
timer = null;
|
|
187
|
+
};
|
|
189
188
|
|
|
190
189
|
defineExpose({
|
|
191
190
|
reset,
|
|
192
191
|
start,
|
|
193
192
|
pause,
|
|
194
|
-
})
|
|
193
|
+
});
|
|
195
194
|
</script>
|
|
196
195
|
|
|
197
196
|
<style scoped lang="scss">
|
|
198
|
-
@import
|
|
197
|
+
@import "./index.scss";
|
|
199
198
|
</style>
|