CountDown.vue 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. <template>
  2. <slot name="renderText" :time="countdown.current.value">
  3. <Text v-bind="$attrs" :text="formatText()" />
  4. </slot>
  5. </template>
  6. <script setup lang="ts">
  7. import Text, { type TextProps } from '@/components/basic/Text.vue';
  8. import { useCountDown } from './CountdownHook';
  9. import { onBeforeUnmount, onMounted, watch } from 'vue';
  10. import { FormatUtils } from '@imengyu/imengyu-utils';
  11. export interface CountDownProps extends TextProps {
  12. /**
  13. * 倒计时时长,单位毫秒
  14. * @default 0
  15. */
  16. time?: number;
  17. /**
  18. * 时间格式
  19. * @default 'HH:mm:ss'
  20. */
  21. format?: string;
  22. /**
  23. * 是否自动开始倒计时
  24. * @default true
  25. */
  26. autoStart?: boolean;
  27. /**
  28. * 是否开启毫秒级渲染
  29. * @default false
  30. */
  31. millisecond?: boolean;
  32. }
  33. export interface CountDownInstance {
  34. start: () => void;
  35. stop: () => void;
  36. reset: (time?: number) => void;
  37. }
  38. const emit = defineEmits<{
  39. /**
  40. * 倒计时结束事件
  41. */
  42. (e: 'finish'): void;
  43. }>();
  44. const props = withDefaults(defineProps<CountDownProps>(), {
  45. time: 0,
  46. format: 'HH:mm:ss',
  47. autoStart: true,
  48. millisecond: false,
  49. });
  50. const countdown = useCountDown({
  51. time: props.time || 0,
  52. millisecond: props.millisecond || false,
  53. onFinish: () => emit('finish'),
  54. });
  55. watch(() => props.time, () => {
  56. countdown.reset(props.time);
  57. });
  58. onMounted(() => {
  59. if (props.autoStart !== false)
  60. countdown.start();
  61. });
  62. onBeforeUnmount(() => {
  63. countdown.stop();
  64. });
  65. defineExpose<CountDownInstance>({
  66. start() { countdown.start(); },
  67. stop() { countdown.stop(); },
  68. reset(time) { countdown.reset(time); },
  69. });
  70. function formatText() {
  71. let str = props.format ? props.format : "HH:mm:ss";
  72. str = str.replace(/DD/, FormatUtils.formatNumberWithZero(countdown.current.value.days, 2));
  73. str = str.replace(/HH/, FormatUtils.formatNumberWithZero(countdown.current.value.hours, 2));
  74. str = str.replace(/mm/, FormatUtils.formatNumberWithZero(countdown.current.value.minutes, 2));
  75. str = str.replace(/ss/, FormatUtils.formatNumberWithZero(countdown.current.value.seconds, 2));
  76. str = str.replace(/SSS/, FormatUtils.formatNumberWithZero(countdown.current.value.milliseconds, 3));
  77. str = str.replace(/SS/, FormatUtils.formatNumberWithZero(Math.floor(countdown.current.value.milliseconds / 10), 2));
  78. str = str.replace(/S/, Math.floor(countdown.current.value.milliseconds / 100).toString());
  79. return str;
  80. }
  81. </script>