count-to1.vue 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. <script setup lang="ts">
  2. import { TransitionPresets, useTransition } from '@vueuse/core'
  3. defineOptions({
  4. name: 'FaCountTo'
  5. })
  6. const props = withDefaults(
  7. defineProps<{
  8. startVal: number
  9. endVal: number
  10. autoplay?: boolean
  11. duration?: number
  12. transition?: keyof typeof TransitionPresets
  13. delay?: number
  14. decimals?: number
  15. separator?: string
  16. prefix?: string
  17. suffix?: string
  18. }>(),
  19. {
  20. autoplay: true,
  21. duration: 2000,
  22. transition: 'linear',
  23. delay: 0,
  24. decimals: 0,
  25. separator: ','
  26. }
  27. )
  28. const emits = defineEmits<{
  29. onStarted: []
  30. onFinished: []
  31. }>()
  32. const disabled = ref(false)
  33. const source = ref(props.startVal)
  34. const outputValue = useTransition(source, {
  35. duration: props.duration,
  36. transition: TransitionPresets[props.transition],
  37. delay: props.delay,
  38. disabled,
  39. onStarted: () => emits('onStarted'),
  40. onFinished: () => emits('onFinished')
  41. })
  42. const value = computed(() => {
  43. let val: number | string = unref(outputValue.value)
  44. val = Number(val).toFixed(props.decimals)
  45. if (props.separator) {
  46. const [integer, decimal] = val.toString().split('.')
  47. val = integer.replace(/\B(?=(\d{3})+(?!\d))/g, props.separator) + (decimal ? `.${decimal}` : '')
  48. }
  49. if (props.prefix) {
  50. val = props.prefix + val
  51. }
  52. if (props.suffix) {
  53. val = val + props.suffix
  54. }
  55. return val
  56. })
  57. function start() {
  58. source.value = props.endVal
  59. }
  60. function reset() {
  61. disabled.value = true
  62. source.value = props.startVal
  63. nextTick(() => {
  64. disabled.value = false
  65. })
  66. }
  67. watch([() => props.startVal, () => props.endVal], () => {
  68. start()
  69. })
  70. onMounted(() => {
  71. props.autoplay && start()
  72. })
  73. defineExpose({
  74. start,
  75. reset
  76. })
  77. </script>
  78. <template>
  79. <span class="flex">
  80. <span v-if="endVal !== null && endVal !== undefined">{{ value }}</span>
  81. <slot v-else></slot>
  82. </span>
  83. </template>