index.tsx 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import { defineComponent, ref, watch, onMounted, computed } from "vue";
  2. const props = {
  3. startVal: {
  4. type: Number,
  5. default: 0
  6. },
  7. endVal: {
  8. type: Number,
  9. default: 2021
  10. },
  11. duration: {
  12. type: Number,
  13. default: 3000
  14. },
  15. autoplay: {
  16. type: Boolean,
  17. default: true
  18. },
  19. decimals: {
  20. type: Number,
  21. default: 0
  22. },
  23. separator: {
  24. type: String,
  25. default: ","
  26. },
  27. prefix: {
  28. type: String,
  29. default: ""
  30. },
  31. suffix: {
  32. type: String,
  33. default: ""
  34. },
  35. fontSize: {
  36. type: String,
  37. default: "16px"
  38. },
  39. color: {
  40. type: String,
  41. default: ""
  42. }
  43. };
  44. export const ReNormalCountTo = defineComponent({
  45. name: "ReNormalCountTo",
  46. props,
  47. emits: ["mounted", "callback"],
  48. setup(props, { emit }) {
  49. const state = ref(props.startVal);
  50. const startTime = ref(0);
  51. const rafId = ref(0);
  52. const formatNumber = computed(() => {
  53. const val = state.value.toFixed(props.decimals);
  54. const parts = val.split(".");
  55. parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, props.separator);
  56. return props.prefix + parts.join(".") + props.suffix;
  57. });
  58. function count(timestamp: number) {
  59. if (!startTime.value) startTime.value = timestamp;
  60. const progress = timestamp - startTime.value;
  61. const remaining = props.duration - progress;
  62. if (remaining < 0) {
  63. state.value = props.endVal;
  64. emit("callback");
  65. return;
  66. }
  67. const rate = progress / props.duration;
  68. state.value = props.startVal + (props.endVal - props.startVal) * rate;
  69. rafId.value = requestAnimationFrame(count);
  70. }
  71. function start() {
  72. startTime.value = 0;
  73. rafId.value = requestAnimationFrame(count);
  74. }
  75. onMounted(() => {
  76. if (props.autoplay) {
  77. start();
  78. }
  79. emit("mounted");
  80. });
  81. watch(
  82. () => props.endVal,
  83. () => {
  84. if (props.autoplay) {
  85. start();
  86. }
  87. }
  88. );
  89. return () => (
  90. <span
  91. style={{
  92. fontSize: props.fontSize,
  93. color: props.color
  94. }}
  95. >
  96. {formatNumber.value}
  97. </span>
  98. );
  99. }
  100. });
  101. export default ReNormalCountTo;