CountTo
17:06Description
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
| Platform | Support |
|---|---|
| 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
<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
<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
<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
<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
<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
<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
<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
| Property | Description | Type | Default | Version |
|---|---|---|---|---|
customStyle | Custom root element style | string | UTSJSONObject | - | - |
customClass | Custom root element style class | string | '' | - |
startVal | Start value; by default it counts up from 0 | number | string | 0 | - |
endVal | Target value to roll to | number | string | 0 | - |
duration | Duration of the roll animation to the target value, in milliseconds (ms) | number | string | 2000 | - |
autoplay | Whether to start rolling automatically once the value is set | boolean | true | - |
decimals | Number of decimal places to display | number | string | 0 | - |
useEasing | Whether to ease out as it approaches the target value | boolean | true | - |
decimal | Decimal point symbol | number | string | '.' | - |
color | Font color | string | '' | - |
fontSize | Font size | number | string | DEFAULT_FONT_SIZE | - |
bold | Whether to bold the font | boolean | false | - |
separator | Thousands separator, like the grouping in money (the "," in ¥23,321.05) | string | '' | - |
Events
| Event | Description | Params | Version |
|---|---|---|---|
end | Fired when the value finishes rolling to the target | - | - |
Slots
ux-count-to has no slots.
Notes
- When
endValorstartValchanges andautoplayis true, it rolls again automatically; withautoplayfalse it only showsstartValinitially and needs a manualstart()call throughref. decimalsdefaults to 0, so the fractional part is rounded away and not shown; setdecimalsexplicitly to show decimals, together withdecimalfor the decimal point symbol (default.).separatoronly groups the integer part with thousands separators (e.g. 233,321); the decimal places are still controlled bydecimals.- With
useEasingtrue it eases out exponentially at the end; with false it runs at a constant rate throughout. - The
endevent fires once when the value finishes rolling to the target (when the animation ends). - When
fontSizeis unset it falls back to the global configcomponentProps['ux-count-to'].fontSizeand then to the built-in default of 25px; whencoloris unset it uses the theme main color. - The animation is driven by a
setTimeout-basedrequestAnimationFramepolyfill (about 60fps), anddurationis the total rolling time. - On App the root element is a block-level
flex, while on H5 / WeChat Mini Program it isinline-flex; multiple counters on App need a wrapping container to sit on one line.