Simple Scrolling Effects
TimeredCounter provides the following components for scrolling different types of data:
- timered-counter-number:
number
,bigint
- timered-counter-datetime-duration:
Date
- timered-counter-string:
string
You can achieve a nice scrolling effect with the default configuration.
TIP
Click the button to observe the change in values.
Scrolling Numbers
Imagine a water meter in real life, it keeps scrolling to show the current water usage. TimeredCounter can help you achieve this effect.

Click to view code
<div class="text-center">
<timered-counter-number id="basic-number-counter" initial-value="114511" />
</div>
<hr />
<div class="flex gap-4">
<input class="border border-solid p-1" v-model="number" />
<button class="border border-solid px-2 py-1" @click="switchNumber">🔄</button>
</div>
import {onMounted, ref, watch} from "vue";
const number = ref(114514);
function switchNumber() {
number.value = Math.floor(Math.random() * 1000000);
}
onMounted(() => watch([number], update, { immediate: true }));
function update() {
const _number = number.value;
const counter = document.getElementById('basic-number-counter');
counter.value = _number;
}
<script setup>
// #region js
import {onMounted, ref, watch} from "vue";
const number = ref(114514);
function switchNumber() {
number.value = Math.floor(Math.random() * 1000000);
}
onMounted(() => watch([number], update, { immediate: true }));
function update() {
const _number = number.value;
const counter = document.getElementById('basic-number-counter');
counter.value = _number;
}
// #endregion js
</script>
<template>
<!-- #region html -->
<div class="text-center">
<timered-counter-number id="basic-number-counter" initial-value="114511" />
</div>
<hr />
<div class="flex gap-4">
<input class="border border-solid p-1" v-model="number" />
<button class="border border-solid px-2 py-1" @click="switchNumber">🔄</button>
</div>
<!-- #endregion html -->
</template>
<style scoped></style>
Countdown Effect
I believe you have seen many countdowns, but most of them change abruptly without transitions. TimeredCounter can make your countdown effect smoother.
Click to view code
<div class="text-center">
<timered-counter-datetime-duration id="basic-datetime-duration-counter" />
</div>
<hr />
<div class="flex gap-4">
<div>
<input
class="border border-solid p-1"
v-model="from"
type="datetime-local"
/>
~
<input
class="border border-solid p-1"
v-model="to"
type="datetime-local"
/>
</div>
</div>
<div class="flex gap-4 mt-4">
<label>
时间范围精度
<select
class="border border-solid p-1 appearance-auto"
v-model="precision[0]"
>
<option
v-for="partType in durationPartTypes"
:key="partType"
:value="partType"
>
{{ partType }}
</option>
</select>
~
<select
class="border border-solid p-1 appearance-auto"
v-model="precision[1]"
>
<option
v-for="partType in durationPartTypes.filter(
(part) =>
DurationPartMillisecond[part] >=
DurationPartMillisecond[precision[0]]
)"
:key="partType"
:value="partType"
>
{{ partType }}
</option>
</select>
</label>
</div>
import {onMounted, ref, watch} from "vue";
import { DurationPartType, DurationPartMillisecond } from "timered-counter";
const from = ref("2024-12-01T00:00:00");
const to = ref("2024-12-31T00:05:30");
const precision = ref([DurationPartType.Second, DurationPartType.Day]);
const durationPartTypes = ref([
DurationPartType.Year,
DurationPartType.Quarter,
DurationPartType.Month,
DurationPartType.Week,
DurationPartType.Day,
DurationPartType.Hour,
DurationPartType.Minute,
DurationPartType.Second,
]);
onMounted(() => watch([from, to, precision], update, { immediate: true }));
function update() {
const _from = from.value;
const _to = to.value;
const _precision = precision.value;
const counter = document.getElementById('basic-datetime-duration-counter');
counter.value = [_from, _to];
counter.precision = [..._precision];
}
<script setup>
// #region js
import {onMounted, ref, watch} from "vue";
import { DurationPartType, DurationPartMillisecond } from "timered-counter";
const from = ref("2024-12-01T00:00:00");
const to = ref("2024-12-31T00:05:30");
const precision = ref([DurationPartType.Second, DurationPartType.Day]);
const durationPartTypes = ref([
DurationPartType.Year,
DurationPartType.Quarter,
DurationPartType.Month,
DurationPartType.Week,
DurationPartType.Day,
DurationPartType.Hour,
DurationPartType.Minute,
DurationPartType.Second,
]);
onMounted(() => watch([from, to, precision], update, { immediate: true }));
function update() {
const _from = from.value;
const _to = to.value;
const _precision = precision.value;
const counter = document.getElementById('basic-datetime-duration-counter');
counter.value = [_from, _to];
counter.precision = [..._precision];
}
// #endregion js
</script>
<template>
<!-- #region html -->
<div class="text-center">
<timered-counter-datetime-duration id="basic-datetime-duration-counter" />
</div>
<hr />
<div class="flex gap-4">
<div>
<input
class="border border-solid p-1"
v-model="from"
type="datetime-local"
/>
~
<input
class="border border-solid p-1"
v-model="to"
type="datetime-local"
/>
</div>
</div>
<div class="flex gap-4 mt-4">
<label>
时间范围精度
<select
class="border border-solid p-1 appearance-auto"
v-model="precision[0]"
>
<option
v-for="partType in durationPartTypes"
:key="partType"
:value="partType"
>
{{ partType }}
</option>
</select>
~
<select
class="border border-solid p-1 appearance-auto"
v-model="precision[1]"
>
<option
v-for="partType in durationPartTypes.filter(
(part) =>
DurationPartMillisecond[part] >=
DurationPartMillisecond[precision[0]]
)"
:key="partType"
:value="partType"
>
{{ partType }}
</option>
</select>
</label>
</div>
<!-- #endregion html -->
</template>
<style scoped></style>
Scrolling Strings
Have you seen the moving title on the homepage? Such an effect can make your static web page more dynamic.
TIP
Please note that the default configuration supports a maximum of 14~15 characters. If you need more characters, please refer to how to remove the character length limit.
Click to view code
<div class="text-center">
<timered-counter-string id="basic-string-counter" value="Hello, World!" />
</div>
<hr />
<div class="flex gap-4">
<input class="border border-solid p-1" v-model="string" />
<button class="border border-solid px-2 py-1" @click="switchString">🔄</button>
</div>
import {onMounted, ref, watch} from "vue";
const string = ref("Hello, World!");
const strings = [
"Hello, World!",
"你好,世界!",
"こんにちは、世界!",
"안녕하세요, 세계!",
// 太长了
// "Bonjour, le monde!",
"Hallo, Welt!",
"Ciao, mondo!",
"Olá, mundo!",
"Привет, мир!",
"¡Hola, mundo!",
"Hej, världen!",
"Merhaba, Dünya!",
"مرحبا بالعالم!",
"שלום, עולם!",
"नमस्ते, दुनिया!",
"سلام دنیا!",
];
let stringIndex = 0;
function switchString() {
stringIndex = (stringIndex + 1) % strings.length;
string.value = strings[stringIndex];
}
onMounted(() => watch([string], update, { immediate: true }));
function update() {
const _string = string.value;
const counter = document.getElementById('basic-string-counter');
counter.value = _string;
}
<script setup>
// #region js
import {onMounted, ref, watch} from "vue";
const string = ref("Hello, World!");
const strings = [
"Hello, World!",
"你好,世界!",
"こんにちは、世界!",
"안녕하세요, 세계!",
// 太长了
// "Bonjour, le monde!",
"Hallo, Welt!",
"Ciao, mondo!",
"Olá, mundo!",
"Привет, мир!",
"¡Hola, mundo!",
"Hej, världen!",
"Merhaba, Dünya!",
"مرحبا بالعالم!",
"שלום, עולם!",
"नमस्ते, दुनिया!",
"سلام دنیا!",
];
let stringIndex = 0;
function switchString() {
stringIndex = (stringIndex + 1) % strings.length;
string.value = strings[stringIndex];
}
onMounted(() => watch([string], update, { immediate: true }));
function update() {
const _string = string.value;
const counter = document.getElementById('basic-string-counter');
counter.value = _string;
}
// #endregion js
</script>
<template>
<!-- #region html -->
<div class="text-center">
<timered-counter-string id="basic-string-counter" value="Hello, World!" />
</div>
<hr />
<div class="flex gap-4">
<input class="border border-solid p-1" v-model="string" />
<button class="border border-solid px-2 py-1" @click="switchString">🔄</button>
</div>
<!-- #endregion html -->
</template>
<style scoped></style>
Next Steps
- To learn how to set language-sensitive number formats, date and time formats, check out Localization.
- If you want to customize the appearance or transition animations of the components, check out Custom Styles and Custom Animations.