Skip to content

CountTo ​

17:06

Description ​

A rolling number component: it eases a value from start-val to end-val within duration (a countdown when start-val is greater than end-val), supporting decimal places, a thousands separator, and text styles such as font size / color / bold. autoplay controls whether it starts automatically after mount, and you can also control it manually via ref with start / stop / reStart / resume / reset.

Compatibility ​

PlatformSupport
App✅ Supported (the root element is a block-level flex, so multiple counters need a wrapping container to sit on one line)
H5✅ Supported
WeChat Mini Program✅ Supported

Examples ​

Basic Usage ​

By default it rolls from 0 to end-val, starts automatically, and ends with easing.

View source
vue
<template>
    <ux-count-to :end-val="965"></ux-count-to>
</template>

Custom Start/End Values ​

Specify the start and end values via start-val / end-val; countdown is also supported.

View source
vue
<template>
    <ux-count-to :start-val="100" :end-val="0"></ux-count-to>
    <view class="gap"></view>
    <ux-count-to :start-val="0" :end-val="9999"></ux-count-to>
</template>

<style scoped>
.gap {
    height: 20px;
}
</style>

Thousands Separator ​

Use separator to add a thousands separator for numbers above four digits.

View source
vue
<template>
    <ux-count-to :end-val="233321.05" separator=","></ux-count-to>
</template>

Show Decimals ​

Control the number of decimal places via decimals; decimal customizes the decimal point symbol.

View source
vue
<template>
    <ux-count-to :end-val="12345.678" :decimals="2"></ux-count-to>
    <view class="gap"></view>
    <ux-count-to :end-val="12345.678" :decimals="2" decimal="."></ux-count-to>
</template>

<style scoped>
.gap {
    height: 20px;
}
</style>

Custom Style ​

Customize the text style via color / font-size / bold.

View source
vue
<template>
    <ux-count-to :end-val="8888" color="#2979ff" :font-size="30" :bold="true"></ux-count-to>
    <view class="gap"></view>
    <ux-count-to :end-val="8888" color="#fa3534"></ux-count-to>
</template>

<style scoped>
.gap {
    height: 20px;
}
</style>

Disable Easing ​

With use-easing=false, the number grows at a constant rate with no easing at the end.

View source
vue
<template>
    <ux-count-to :end-val="5000" :use-easing="false"></ux-count-to>
</template>

Animation Control ​

Control the rolling duration (ms) via duration, whether to start automatically via autoplay, or trigger start manually.

View source
vue
<template>
    <ux-count-to ref="countToRef" :end-val="965" :duration="rollDuration" :autoplay="rollAutoPlay"></ux-count-to>
    <view class="gap"></view>
    <view class="btn-row">
        <view class="btn" @click="startRoll"><text class="btn-text">开始</text></view>
        <view class="btn" @click="toggleAutoPlay"><text class="btn-text">{{ rollAutoPlay ? '自动开' : '自动关' }}</text></view>
        <view class="btn" @click="setDuration(500)"><text class="btn-text">500ms</text></view>
        <view class="btn" @click="setDuration(2000)"><text class="btn-text">2000ms</text></view>
        <view class="btn" @click="setDuration(5000)"><text class="btn-text">5000ms</text></view>
    </view>
</template>

<script setup lang="uts">
const countToRef = ref<any>();
const rollDuration = ref<number>(2000);
const rollAutoPlay = ref<boolean>(true);

function startRoll(): void {
    countToRef.value?.start();
}

function toggleAutoPlay(): void {
    rollAutoPlay.value = !rollAutoPlay.value;
}

function setDuration(ms: number): void {
    rollDuration.value = ms;
    countToRef.value?.start();
}
</script>

<style scoped>
.gap {
    height: 20px;
}
.btn-row {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    margin-top: 8px;
}
.btn {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    padding: 4px 12px;
    margin-right: 8px;
    margin-bottom: 8px;
    border-radius: 4px;
    background-color: #ecf5ff;
}
.btn-text {
    font-size: 13px;
    color: #2979ff;
}
</style>

API ​

Props ​

PropertyDescriptionTypeDefaultVersion
customStyleCustom root element stylestring | UTSJSONObject--
customClassCustom root element style classstring''-
startValStart value; by default it counts up from 0number | string0-
endValTarget value to roll tonumber | string0-
durationDuration of the roll animation to the target value, in milliseconds (ms)number | string2000-
autoplayWhether to start rolling automatically once the value is setbooleantrue-
decimalsNumber of decimal places to displaynumber | string0-
useEasingWhether to ease out as it approaches the target valuebooleantrue-
decimalDecimal point symbolnumber | string'.'-
colorFont colorstring''-
fontSizeFont sizenumber | stringDEFAULT_FONT_SIZE-
boldWhether to bold the fontbooleanfalse-
separatorThousands separator, like the grouping in money (the "," in ¥23,321.05)string''-

Events ​

EventDescriptionParamsVersion
endFired when the value finishes rolling to the target--

Slots ​

ux-count-to has no slots.

Notes ​

  1. When endVal or startVal changes and autoplay is true, it rolls again automatically; with autoplay false it only shows startVal initially and needs a manual start() call through ref.
  2. decimals defaults to 0, so the fractional part is rounded away and not shown; set decimals explicitly to show decimals, together with decimal for the decimal point symbol (default .).
  3. separator only groups the integer part with thousands separators (e.g. 233,321); the decimal places are still controlled by decimals.
  4. With useEasing true it eases out exponentially at the end; with false it runs at a constant rate throughout.
  5. The end event fires once when the value finishes rolling to the target (when the animation ends).
  6. When fontSize is unset it falls back to the global config componentProps['ux-count-to'].fontSize and then to the built-in default of 25px; when color is unset it uses the theme main color.
  7. The animation is driven by a setTimeout-based requestAnimationFrame polyfill (about 60fps), and duration is the total rolling time.
  8. On App the root element is a block-level flex, while on H5 / WeChat Mini Program it is inline-flex; multiple counters on App need a wrapping container to sit on one line.