import { defineComponent, ref, watch, onMounted, computed } from "vue"; const props = { startVal: { type: Number, default: 0 }, endVal: { type: Number, default: 2021 }, duration: { type: Number, default: 3000 }, autoplay: { type: Boolean, default: true }, decimals: { type: Number, default: 0 }, separator: { type: String, default: "," }, prefix: { type: String, default: "" }, suffix: { type: String, default: "" }, fontSize: { type: String, default: "16px" }, color: { type: String, default: "" } }; export const ReNormalCountTo = defineComponent({ name: "ReNormalCountTo", props, emits: ["mounted", "callback"], setup(props, { emit }) { const state = ref(props.startVal); const startTime = ref(0); const rafId = ref(0); const formatNumber = computed(() => { const val = state.value.toFixed(props.decimals); const parts = val.split("."); parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, props.separator); return props.prefix + parts.join(".") + props.suffix; }); function count(timestamp: number) { if (!startTime.value) startTime.value = timestamp; const progress = timestamp - startTime.value; const remaining = props.duration - progress; if (remaining < 0) { state.value = props.endVal; emit("callback"); return; } const rate = progress / props.duration; state.value = props.startVal + (props.endVal - props.startVal) * rate; rafId.value = requestAnimationFrame(count); } function start() { startTime.value = 0; rafId.value = requestAnimationFrame(count); } onMounted(() => { if (props.autoplay) { start(); } emit("mounted"); }); watch( () => props.endVal, () => { if (props.autoplay) { start(); } } ); return () => ( {formatNumber.value} ); } }); export default ReNormalCountTo;