---
url: /en/guide/examples/animated-usage.md
---
# Custom Animation {#animated-usage}
> This section assumes you have some understanding of [CSS animations](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animations) or [CSS transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_transitions).
>
> If you are not familiar with CSS animations or CSS transitions, it is recommended to learn about them first.
## Delay {#delay}
::: details Click to view code
::: code-group
<<< @/components/AdvancedDelayDemo.vue#html{html} \[HTML]
<<< @/components/AdvancedDelayDemo.vue#js{js} \[JS]
<<< @/components/AdvancedDelayDemo.vue{vue} \[All]
:::
## Easing {#easing}
To make it easier to observe the easing effect, the animation duration has been adjusted and the font size increased.
::: details Click to view code
::: code-group
<<< @/components/AdvancedEasingDemo.vue#html{html} \[HTML]
<<< @/components/AdvancedEasingDemo.vue#js{js} \[JS]
<<< @/components/AdvancedEasingDemo.vue{vue} \[All]
<<< @/components/EasingView.vue{vue} \[EasingView.vue]
:::
---
---
url: /en/guide/examples/styled-usage.md
---
# Custom Styles {#styled-usage}
### Custom Colors {#color}
> To better observe the changes in fill color, the font size has been increased.
::: details Click to view code
::: code-group
<<< @/components/ColorfulNumberDemo.vue#html{html} \[HTML]
<<< @/components/ColorfulNumberDemo.vue#js{js} \[JS]
<<< @/components/ColorfulNumberDemo.vue{vue} \[All]
:::
### Custom Fonts {#font}
You can directly customize various font properties by setting CSS properties.
::: details Click to view code
::: code-group
<<< @/components/PlayfulNumberDemo.vue#html{html} \[HTML]
<<< @/components/PlayfulNumberDemo.vue#js{js} \[JS]
<<< @/components/PlayfulNumberDemo.vue{vue} \[All]
<<< @/components/GoogleFontPicker.vue{vue} \[GoogleFontPicker.vue]
:::
---
---
url: /en/guide/getting-started.md
---
# Getting Started {#getting-started}
::: tip Note
TimeredCounter currently has two optional dependencies. Considering their large size, they are not installed by default. You can manually install them as needed.
* **decimal.js**: Decimal.js provides almost unlimited precision for handling large numbers/high-precision floating-point calculations. [How to use ->](optional-dependencies#character-length-limit)
* **grapheme-splitter**: grapheme-splitter can correctly split strings containing emojis. [How to use ->](optional-dependencies.md#support-emoji-segmentation)
**In each usage method below, we will provide instructions on how to install these two dependencies.**
:::
## Import via CDN {#import-via-cdn}
You can use TimeredCounter directly via CDN with the `
```
Here we use [jsdelivr](https://jsdelivr.com), but you can also use any CDN that provides npm packages, such as [unpkg](https://unpkg.com/timered-counter) or [cdnjs](https://cdnjs.com/libraries/timered-counter). Of course, you can also download this file and serve it yourself.
Using TimeredCounter via CDN does not involve a "build step". This makes setup simpler and can be used to enhance static HTML.
### Using Global Build Version {#global-build}
The above link uses the global build version of TimeredCounter, where all top-level APIs are exposed as properties on the global TimeredCounter object. Here is an example of using the global build version:
```html
...
```
#### Optional Dependencies
::: details Add `decimal.js` Number Adapter
If you need to use the `decimal.js` based number adapter, please add the following `
```
Then import it in your code:
```javascript
TimeredCounter.registerAdapter(TimeredCounterExternal.DecimalJsNumberAdapter); // Register adapter
TimeredCounter.setNumberAdapter('decimal.js'); // Set the adapter to use
```
:::
::: details Add `grapheme-splitter` String Adapter
If you need to use the `grapheme-splitter` based string adapter, please add the following `
```
Then import it in your code:
```javascript
TimeredCounter.registerAdapter(TimeredCounterExternal.GraphemeSplitterStringAdapter); // Register adapter
TimeredCounter.setStringAdapter('grapheme-splitter'); // Set the adapter to use
```
:::
::: details File Size
| File Name | raw | gzip | brotli | deflate |
|---------------------------|------------------------------------------------------|------------------|------------------|------------------|
| timered-counter.global.js | {{ filesize(umd\['timered-counter.global.js'].raw) }} | {{ filesize(umd\['timered-counter.global.js'].gzip) }} | {{ filesize(umd\['timered-counter.global.js'].brotli) }} | {{ filesize(umd\['timered-counter.global.js'].deflate) }} |
| decimal-js-number-adapter.global.js | {{ filesize(umd\['decimal-js-number-adapter.global.js'].raw) }} | {{ filesize(umd\['decimal-js-number-adapter.global.js'].gzip) }} | {{ filesize(umd\['decimal-js-number-adapter.global.js'].brotli) }} | {{ filesize(umd\['decimal-js-number-adapter.global.js'].deflate) }} |
| grapheme-splitter-string-adapter.global.js | {{ filesize(umd\['grapheme-splitter-string-adapter.global.js'].raw) }} | {{ filesize(umd\['grapheme-splitter-string-adapter.global.js'].gzip) }} | {{ filesize(umd\['grapheme-splitter-string-adapter.global.js'].brotli) }} | {{ filesize(umd\['grapheme-splitter-string-adapter.global.js'].deflate) }} |
### Using ES Module Build Version {#es-module-build}
In the rest of this document, we mainly use ES module syntax. Most modern browsers natively support ES modules. Therefore, we can use TimeredCounter via CDN and native ES modules like this:
```html
...
```
Note that we use `
```
:::
::: details Add `grapheme-splitter` String Adapter
If you need to use the `grapheme-splitter` based string adapter, please modify the code as follows:
```html
```
:::
::: details File Size
| File Name | raw | gzip | brotli | deflate |
|---------------------------|-----------------------------------------------------------------------|------------------|------------------|------------------|
| timered-counter.esm-browser.js | {{ filesize(esm\['timered-counter.esm-browser.js'].raw) }} | {{ filesize(esm\['timered-counter.esm-browser.js'].gzip) }} | {{ filesize(esm\['timered-counter.esm-browser.js'].brotli) }} | {{ filesize(esm\['timered-counter.esm-browser.js'].deflate) }} |
| decimal-js-number-adapter.esm-browser.js | {{ filesize(esm\['decimal-js-number-adapter.esm-browser.js'].raw) }} | {{ filesize(esm\['decimal-js-number-adapter.esm-browser.js'].gzip) }} | {{ filesize(esm\['decimal-js-number-adapter.esm-browser.js'].brotli) }} | {{ filesize(esm\['decimal-js-number-adapter.esm-browser.js'].deflate) }} |
| grapheme-splitter-string-adapter.esm-browser.js | {{ filesize(esm\['grapheme-splitter-string-adapter.esm-browser.js'].raw) }} | {{ filesize(esm\['grapheme-splitter-string-adapter.esm-browser.js'].gzip) }} | {{ filesize(esm\['grapheme-splitter-string-adapter.esm-browser.js'].brotli) }} | {{ filesize(esm\['grapheme-splitter-string-adapter.esm-browser.js'].deflate) }} |
## Import via Module {#import-via-module}
### Installation {#installation}
::: code-group
```shell [npm]
$ npm install timered-counter --save
```
```shell [pnpm]
$ pnpm add timered-counter
```
```shell [yarn]
$ yarn add timered-counter
```
:::
### Import {#import}
```javascript
import "timered-counter";
```
#### Optional Dependencies
::: details Install `decimal.js` Number Adapter
If you need to use the `decimal.js` based number adapter, please install it first:
```shell
npm install decimal.js --save
```
Then import it in your code:
```javascript
import { setNumberAdapter, registerAdapter } from "timered-counter";
import DecimalJsNumberAdapter from "timered-counter/number-adapter/decimal-js.js";
registerAdapter(DecimalJsNumberAdapter); // Register adapter
setNumberAdapter('decimal.js'); // Set the adapter to use
```
:::
::: details Install `grapheme-splitter` String Adapter
If you need to use the `grapheme-splitter` based string adapter, please install it first:
```shell
npm install grapheme-splitter --save
```
Then import it in your code:
```javascript
import { setStringAdapter, registerAdapter } from "timered-counter";
import GraphemeSplitterStringAdapter from "timered-counter/string-adapter/grapheme-splitter.js";
registerAdapter(GraphemeSplitterStringAdapter); // Register adapter
setStringAdapter('grapheme-splitter'); // Set the adapter to use
```
:::
## Usage {#usage}
You only need to update the value, and `TimeredCounter` will handle the rest automatically.
Below is a simple example where `TimeredCounter` will automatically respond to changes in the number and handle the increment/decrement animation.
::: code-group
<<< @/components/GettingStartedDemo.vue#html{html} \[HTML]
<<< @/components/GettingStartedDemo.vue#js{js} \[JS]
<<< @/components/GettingStartedDemo.vue{vue} \[All]
:::
## Next {#next}
* Want to see more examples of `TimeredCounter`? Check out [Examples](./examples/simple-usage).
* Want to learn about `TimeredCounter` configuration parameters? Check out [Configuration and API](../reference/api).
* Want to explore more possibilities of `TimeredCounter` styles and animations, such as achieving [this](./examples/logo) effect? You can start from [In-depth TimeredCounter](./timered-counter-in-depth).
---
---
url: /en/guide/timered-counter-in-depth.md
---
# In-depth TimeredCounter {#timered-counter-in-depth}
## Structure {#structure}
TimeredCounter consists of \, \, \ | , and \. You can see these parts annotated in the example below.
The \ is an optional part. In the example below, it is used to display time units (day, hour).
### Hierarchy {#hierarchy}
Using the example above as a reference, the hierarchy of TimeredCounter is as follows:
```
part -> digit -> cell
-> digit -> cell
-> suffix (day)
part -> digit -> cell
-> digit -> cell
-> suffix (hour)
```
## Usage {#usage}
> For simple usage (such as [simple scrolling effect](./examples/simple-usage), [localization](./examples/locale-usage)), you don't need to worry about the implementation details of TimeredCounter.
>
> However, when we need to customize animation effects, such as (), or need to customize the style of each digit, understanding the structure of TimeredCounter is essential.
To provide enough freedom to customize animation effects and styles, you can use
1. `animationOptions` to set animation properties down to the level.
2. `cellStyle` to set style properties down to the level.
### Set Animation Options {#set-animation-options}
`animationOptions` is the second parameter of [`Element.animate(keyframes, options)`](https://developer.mozilla.org/en-US/docs/Web/API/Element/animate#options), where you can set animation properties such as `duration`, `delay`, `easing`, etc.
The configuration can take the following forms:
* An object containing the configuration items you set, which will be applied to all .
```js
{ duration: 0.5, delay: 0.1 }
```
* A one-dimensional array, which will be applied to all in the corresponding .
```js
[
{ duration: 0.5, delay: 0.1 }, // part 1
{ duration: 0.5, delay: 0.4 }, // part 2
...
]
```
* A two-dimensional array, which will be applied to the corresponding in the corresponding .
```js
[
[ // part 1
{ duration: 0.5, delay: 0.1 }, // digit 1
{ duration: 0.5, delay: 0.4 }, // digit 2
...
],
...
]
```
* A callback function that accepts an object containing:
* `preprocessData`: a two-dimensional array containing the test results for each .
* `data`: the data used for scrolling. Contains the data for constructing the scroll list for each .
* `direction`: the direction of scrolling. `up` or `down`.
* `value`: the new and old values of the number.
The return value of the function can be one of the three forms above.
For example, in the [delay example](./examples/animated-usage#delay), after enabling **delayed increment**, the animation delay for each is set to achieve the effect of incremental delay.
<<< @/components/AdvancedDelayDemo.vue#increaseDelay{16-18 js}
### Custom Style {#custom-style}
`cellStyle` is a `CSSProperties` object where you can set the style of .
The configuration forms add one more layer on top of `animationOptions`:
* A three-dimensional array, which will be applied to the corresponding in the corresponding in the corresponding .
```js
[
[
// part 1
[
// digit 1
{ color: "red" }, // cell 1
{ color: "blue" }, // cell 2
],
],
];
```
* The callback function form is the same as `animationOptions`. It can also return a three-dimensional array.
---
---
url: /en/guide/examples/locale-usage.md
---
# Localization (Internationalization) {#locale-usage}
TimeredCounter provides localization features for necessary components.
The [timered-counter-number](#locale-number) and [timered-counter-datetime-duration](#locale-datetime-duration) components support localization, and you can set the localization configuration through the `locale` attribute.
In most cases, you only need to set the `locale` attribute to a **language code** (such as `en`, `en-US`, `zh`, `zh-CN`).
TimeredCounter will internally call the [Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) API to handle localization.
## Datetime Duration Localization {#locale-datetime-duration}
::: details Click to view code
::: code-group
<<< @/components/LocaleDatetimeDurationDemo.vue#html{html} \[HTML]
<<< @/components/LocaleDatetimeDurationDemo.vue#js{js} \[JS]
<<< @/components/LocaleDatetimeDurationDemo.vue{vue} \[All]
<<< @/components/LocaleSelect.vue{vue} \[LocaleSelect.vue]
:::
## Number Localization {#locale-number}
Specifically, the `timered-counter-number` component also needs to set the `locale-number` attribute.
* You can set it to `true`, which will enable number localization with the default configuration.
* You can also set it to options supported by [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options).
::: details Click to view code
::: code-group
<<< @/components/LocaleNumberDemo.vue#html{html} \[HTML]
<<< @/components/LocaleNumberDemo.vue#js{js} \[JS]
<<< @/components/LocaleNumberDemo.vue{vue} \[All]
<<< @/components/LocaleSelect.vue{vue} \[LocaleSelect.vue]
:::
---
---
url: /markdown-examples.md
---
# Markdown Extension Examples
This page demonstrates some of the built-in markdown extensions provided by VitePress.
## Syntax Highlighting
VitePress provides Syntax Highlighting powered by [Shiki](https://github.com/shikijs/shiki), with additional features like line-highlighting:
**Input**
````md
```js{4}
export default {
data () {
return {
msg: 'Highlighted!'
}
}
}
```
````
**Output**
```js{4}
export default {
data () {
return {
msg: 'Highlighted!'
}
}
}
```
## Custom Containers
**Input**
```md
::: info
This is an info box.
:::
::: tip
This is a tip.
:::
::: warning
This is a warning.
:::
::: danger
This is a dangerous warning.
:::
::: details
This is a details block.
:::
```
**Output**
::: info
This is an info box.
:::
::: tip
This is a tip.
:::
::: warning
This is a warning.
:::
::: danger
This is a dangerous warning.
:::
::: details
This is a details block.
:::
## More
Check out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown).
---
---
url: /en/guide/optional-dependencies.md
---
# Optional Dependencies {#optional-dependencies}
## Character Length Limit {#character-length-limit}
> TL;DR: [Solution](#how-to-remove-character-length-limit).
`TimeredCounter` works by treating strings as numbers in a certain base and then converting them to decimal numbers. This approach is convenient for sampling numbers to create scrolling lists.
This method works in most cases, but problems arise when the numbers are too large or too small.
According to the ECMA specification, when `number < 10^-5 || number > 10^21`, numbers are represented in scientific notation[^1][^2].
This causes a problem as numbers represented in scientific notation lose some precision.
```
1234567891012131415161
=> 1.2345678910121315e+21 // lost precision for the last 6 digits
```
Due to the implementation, this issue is more likely to occur with `timered-counter-string`.
The base is essentially the number of unique characters in the string, which can easily result in a number exceeding `10^21`.
Similarly, when using `timered-counter-number`, if the value is less than `10^-5`, the number will also be represented in scientific notation.
### How to Remove Character Length Limit {#how-to-remove-character-length-limit}
To solve this problem, we need to use a third-party high-precision calculation library like [decimal.js](https://mikemcl.github.io/decimal.js). `TimeredCounter` provides two adapters:
1. `BuildInNumberAdapter` (default): Uses `Number`.
2. `DecimalJsAdapter`: Uses `decimal.js`, requires installing [decimal.js](https://mikemcl.github.io/decimal.js).
3. Of course, you can implement your own adapter by implementing the `NumberAdapter` interface.
In the example below, you can switch adapters to see the effect.
> `{{ Number.MAX_SAFE_INTEGER }}` is the largest integer that can be accurately represented in JavaScript. When the value exceeds this, precision is lost. You can try inputting:
>
> 1. `{{ BigInt(Number.MAX_SAFE_INTEGER) + 1n }}`: {{ Number.MAX\_SAFE\_INTEGER }} **+ 1**
> 2. `{{ BigInt(Number.MAX_SAFE_INTEGER) + 10n }}`: {{ Number.MAX\_SAFE\_INTEGER }} **+ 10**
> 3. `{{ BigInt(Number.MAX_SAFE_INTEGER) + 100n }}`: {{ Number.MAX\_SAFE\_INTEGER }} **+ 100**
>
> Observe the precision loss.
::: details Click to view code
::: code-group
<<< @/components/NumberAdapterDemo.vue{vue} \[NumberAdapterDemo.vue]
:::
## Support Emoji Segmentation {#support-emoji-segmentation}
For general `emoji`, we can use the default configuration, but for some **special** `emoji`, like `👨👩👧👦`, which are called `Emoji ZWJ Sequence` and are composed of multiple `emoji`.
In this case, it is difficult to correctly recognize strings containing such `emoji`. We can use [Intl.Segmenter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter) or third-party libraries like [grapheme-splitter](https://github.com/orling/grapheme-splitter). `TimeredCounter` provides three adapters:
1. `BuildInStringAdapter` (default): Uses `String.split("")` to split strings.
2. `IntlSegmenterAdapter`: Uses `Intl.Segmenter`, requires browser support.
3. `GraphemeSplitterAdapter`: Uses `grapheme-splitter`, requires installing [grapheme-splitter](https://github.com/orling/grapheme-splitter).
In the example below, you can switch adapters to see the effect.
> You can try inputting the following characters to see the effect.
>
> * `⌚`: Basic emoji
> * `↔️`: Text character rendered as emoji
> * `👩`: Modifiable basic emoji
> * `👩🏿`: Modifiable basic emoji + emoji modifier
> * `🧑💻`: Emoji combination sequence
::: details Click to view code
::: code-group
<<< @/components/StringAdapterDemo.vue{vue} \[StringAdapterDemo.vue]
:::
[^1]: https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-numeric-types-number-tostring
[^2]: https://medium.com/@anna7/large-numbers-in-js-4feb6269d29b
---
---
url: /api-examples.md
---
# Runtime API Examples
This page demonstrates usage of some of the runtime APIs provided by VitePress.
The main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files:
```md
## Results
### Theme Data
{{ theme }}
### Page Data
{{ page }}
### Page Frontmatter
{{ frontmatter }}
```
## Results
### Theme Data
### Page Data
### Page Frontmatter
## More
Check out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata).
---
---
url: /en/guide/examples/simple-usage.md
---
# Simple Scrolling Effects {#simple-usage}
TimeredCounter provides the following components for scrolling different types of data:
* [timered-counter-number](#number): `number`, `bigint`
* [timered-counter-datetime-duration](#datetime): `Date`
* [timered-counter-string](#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 {#number}
Imagine a water meter in real life, it keeps scrolling to show the current water usage. TimeredCounter can help you achieve this effect.
::: details Click to view code
::: code-group
<<< @/components/BasicNumberDemo.vue#html{html} \[HTML]
<<< @/components/BasicNumberDemo.vue#js{js} \[JS]
<<< @/components/BasicNumberDemo.vue{vue} \[All]
:::
## Countdown Effect {#datetime-duration}
I believe you have seen many countdowns, but most of them change abruptly without transitions. TimeredCounter can make your countdown effect smoother.
::: details Click to view code
::: code-group
<<< @/components/BasicDatetimeDurationDemo.vue#html{html} \[HTML]
<<< @/components/BasicDatetimeDurationDemo.vue#js{js} \[JS]
<<< @/components/BasicDatetimeDurationDemo.vue{vue} \[All]
:::
## Scrolling Strings {#string}
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](../optional-dependencies.md#how-to-remove-character-length-limit).
:::
::: details Click to view code
::: code-group
<<< @/components/BasicStringDemo.vue#html{html} \[HTML]
<<< @/components/BasicStringDemo.vue#js{js} \[JS]
<<< @/components/BasicStringDemo.vue{vue} \[All]
:::
## Next Steps {#next}
* To learn how to set language-sensitive number formats, date and time formats, check out [Localization](locale-usage.md).
* If you want to customize the appearance or transition animations of the components, check out [Custom Styles](styled-usage.md) and [Custom Animations](animated-usage.md).
---
---
url: /en/guide/examples/logo.md
---
# TimeredCounter Logo {#logo}
## Example {#example}
::: warning
This example contains some **hacks that seem to work**. Please do not use this code in a production environment, it is for learning purposes only.
:::
::: details Click to view code
::: code-group
<<< @/components/TimeredCounterLogo.vue{vue} \[TimeredCounterLogo.vue]
:::
---
---
url: /zh/guide/examples/logo.md
---
# TimeredCounter Logo {#logo}
## 示例 {#example}
::: warning
该示例包含一些**看起来可以运行的 hack**,请不要在正式环境中使用此代码,仅供学习参考。
:::
::: details 点击查看代码
::: code-group
<<< @/components/TimeredCounterLogo.vue{vue} \[TimeredCounterLogo.vue]
:::
---
---
url: /zh/guide/what-is-timered-counter.md
---
# TimeredCounter 是什么? {#what-is-timered-counter}
TimeredCounter 是一个用于展示**数值变化**的 Web Components 组件,它可以在数值变化时增加动画效果。
## 使用场景 {#usage-scenarios}
* **站点首屏**
本文档的[首页标题](/)()就是一个例子。它可以为你的站点增加一些动态效果,使其看起来更加生动。
* **数据展示**
TimeredCounter 很适合用来展示实时数据,统计数据等。比如,你可以使用它来展示:
* 今天已有 访问了你的网站。 [->](./examples/simple-usage#number)
* 距离下个月还有 [->](./examples/simple-usage#倒计时效果)
::: tip
TimeredCounter 还通过 [Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) 支持国际化。你可以在右上角切换语言来查看效果。
:::
[//]: # " * 你的网站已经运行了 了"
## 性能
TimeredCounter 在内部使用 [Web Animation API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API) 来实现动画效果,因此它的性能表现非常好。
---
---
url: /en.md
---
---
---
url: /en/reference/api.md
---
---
---
url: /zh.md
---
---
---
url: /zh/reference/api.md
---
---
---
url: /en/guide/integration/vue.md
---
# Vue Integration
## Installation
First, please follow the [Getting Started](../getting-started.md) documentation to install.
## Import
In a Vue project, you can import `timered-counter` in the following ways:
Globally register `timered-counter` in the project entry file:
```typescript
import { createApp } from 'vue';
import TimeredCounter from 'timered-counter/vue';
import App from './App';
const app = createApp(App);
app.use(TimeredCounter).mount('#app');
```
---
---
url: /zh/guide/integration/vue.md
---
# Vue 集成
## 安装
首先,请先按照 [快速开始](../getting-started.md) 文档进行安装。
## 导入
在 Vue 项目中,你可以通过以下方式导入 `timered-counter`:
在项目入口文件中全局注册 `timered-counter`:
```typescript
import { createApp } from 'vue';
import TimeredCounter from 'timered-counter/vue';
import App from './App';
const app = createApp(App);
app.use(TimeredCounter).mount('#app');
```
---
---
url: /en/guide/what-is-timered-counter.md
---
# What is TimeredCounter? {#what-is-timered-counter}
TimeredCounter is a Web Components component used to display **value changes** with animation effects when the values change.
## Usage Scenarios {#usage-scenarios}
* **Homepage Header**
The [homepage title](/) of this documentation () is an example. It can add some dynamic effects to your site, making it look more vivid.
* **Data Display**
TimeredCounter is very suitable for displaying real-time data, statistical data, etc. For example, you can use it to display:
* Today, have visited your website. [->](./examples/simple-usage#number)
* There are left until next month. [->](./examples/simple-usage#countdown-effect)
::: tip
TimeredCounter also supports internationalization through [Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl). You can switch the language in the upper right corner to see the effect.
:::
[//]: # " * Your website has been running for "
## Performance
TimeredCounter uses the [Web Animation API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API) internally to achieve animation effects, so its performance is very good.
---
---
url: /zh/guide/getting-started.md
---
# 快速开始 {#getting-started}
::: tip 注意
TimeredCounter 目前有两个可选的依赖项,考虑到它们的体积较大,所以默认情况下不会被安装。你可以根据需要手动安装它们。
* **decimal.js**: Decimal.js 提供了近乎无限制的精度,用于处理大数/高精度浮点数计算。[如何使用 ->](optional-dependencies#character-length-limit)
* **grapheme-splitter**: grapheme-splitter 可以正确地分割包含 emoji 的字符串。[如何使用 ->](optional-dependencies.md#support-emoji-segmentation)
**在下方的每种使用方式中,我们都会提供如何安装这两个依赖的方法。**
:::
## 通过 CDN 引入 {#import-via-cdn}
你可以借助 `
```
这里我们使用了 [jsdelivr](https://jsdelivr.com),但你也可以使用任何提供 npm 包服务的 CDN,例如 [unpkg](https://unpkg.com/timered-counter) 或 [cdnjs](https://cdnjs.com/libraries/timered-counter)。当然,你也可以下载此文件并自行提供服务。
通过 CDN 使用 TimeredCounter 时,不涉及“构建步骤”。这使得设置更加简单,并且可以用于增强静态的 HTML。
### 使用全局构建版本 {#global-build}
上面的链接使用了全局构建版本的 TimeredCounter,该版本的所有顶层 API 都以属性的形式暴露在了全局的 TimeredCounter 对象上。这里有一个使用全局构建版本的例子:
```html
...
```
#### 可选依赖
::: details 添加 `decimal.js` 数字适配器
如果你需要使用基于 `decimal.js` 的数字适配器,请先添加下列 `
```
然后在你的代码中引入:
```javascript
TimeredCounter.registerAdapter(TimeredCounterExternal.DecimalJsNumberAdapter); // 注册适配器
TimeredCounter.setNumberAdapter('decimal.js'); // 设置使用的适配器
```
:::
::: details 添加 `grapheme-splitter` 字符串适配器
如果你需要使用基于 `grapheme-splitter` 的字符串适配器,请先安装它:
```html
```
然后在你的代码中引入:
```javascript
TimeredCounter.registerAdapter(TimeredCounterExternal.GraphemeSplitterStringAdapter); // 注册适配器
TimeredCounter.setStringAdapter('grapheme-splitter'); // 设置使用的适配器
```
:::
::: details 文件体积
| 文件名 | raw | gzip | brotli | deflate |
|---------------------------|------------------------------------------------------|------------------|------------------|------------------|
| timered-counter.global.js | {{ filesize(umd\['timered-counter.global.js'].raw) }} | {{ filesize(umd\['timered-counter.global.js'].gzip) }} | {{ filesize(umd\['timered-counter.global.js'].brotli) }} | {{ filesize(umd\['timered-counter.global.js'].deflate) }} |
| decimal-js-number-adapter.global.js | {{ filesize(umd\['decimal-js-number-adapter.global.js'].raw) }} | {{ filesize(umd\['decimal-js-number-adapter.global.js'].gzip) }} | {{ filesize(umd\['decimal-js-number-adapter.global.js'].brotli) }} | {{ filesize(umd\['decimal-js-number-adapter.global.js'].deflate) }} |
| grapheme-splitter-string-adapter.global.js | {{ filesize(umd\['grapheme-splitter-string-adapter.global.js'].raw) }} | {{ filesize(umd\['grapheme-splitter-string-adapter.global.js'].gzip) }} | {{ filesize(umd\['grapheme-splitter-string-adapter.global.js'].brotli) }} | {{ filesize(umd\['grapheme-splitter-string-adapter.global.js'].deflate) }} |
### 使用 ES 模块构建版本 {#es-module-build}
在本文档的其余部分我们使用的主要是 ES 模块语法。现代浏览器大多都已原生支持 ES 模块。因此我们可以像这样通过 CDN 以及原生 ES 模块使用 TimeredCounter:
```html
...
```
注意我们使用了 `
```
:::
::: details 添加 `grapheme-splitter` 字符串适配器
如果你需要使用基于 `grapheme-splitter` 的字符串适配器,请根据下列代码进行修改:
```html
```
:::
::: details 文件体积
| 文件名 | raw | gzip | brotli | deflate |
|---------------------------|-----------------------------------------------------------------------|------------------|------------------|------------------|
| timered-counter.esm-browser.js | {{ filesize(esm\['timered-counter.esm-browser.js'].raw) }} | {{ filesize(esm\['timered-counter.esm-browser.js'].gzip) }} | {{ filesize(esm\['timered-counter.esm-browser.js'].brotli) }} | {{ filesize(esm\['timered-counter.esm-browser.js'].deflate) }} |
| decimal-js-number-adapter.esm-browser.js | {{ filesize(esm\['decimal-js-number-adapter.esm-browser.js'].raw) }} | {{ filesize(esm\['decimal-js-number-adapter.esm-browser.js'].gzip) }} | {{ filesize(esm\['decimal-js-number-adapter.esm-browser.js'].brotli) }} | {{ filesize(esm\['decimal-js-number-adapter.esm-browser.js'].deflate) }} |
| grapheme-splitter-string-adapter.esm-browser.js | {{ filesize(esm\['grapheme-splitter-string-adapter.esm-browser.js'].raw) }} | {{ filesize(esm\['grapheme-splitter-string-adapter.esm-browser.js'].gzip) }} | {{ filesize(esm\['grapheme-splitter-string-adapter.esm-browser.js'].brotli) }} | {{ filesize(esm\['grapheme-splitter-string-adapter.esm-browser.js'].deflate) }} |
## 通过模块引入 {#import-via-module}
### 安装 {#installation}
::: code-group
```shell [npm]
$ npm install timered-counter --save
```
```shell [pnpm]
$ pnpm add timered-counter
```
```shell [yarn]
$ yarn add timered-counter
```
:::
### 引入 {#import}
```javascript
import "timered-counter";
```
#### 可选依赖
::: details 安装 `decimal.js` 数字适配器
如果你需要使用基于 `decimal.js` 的数字适配器,请先安装它:
```shell
npm install decimal.js --save
```
然后在你的代码中引入:
```javascript
import { setNumberAdapter, registerAdapter } from "timered-counter";
import DecimalJsNumberAdapter from "timered-counter/number-adapter/decimal-js.js";
registerAdapter(DecimalJsNumberAdapter); // 注册内置的 decimal.js 适配器
setNumberAdapter('decimal.js'); // 设置使用的适配器
```
:::
::: details 安装 `grapheme-splitter` 字符串适配器
如果你需要使用基于 `grapheme-splitter` 的字符串适配器,请先安装它:
```shell
npm install grapheme-splitter --save
```
然后在你的代码中引入:
```javascript
import { setStringAdapter, registerAdapter } from "timered-counter";
import GraphemeSplitterStringAdapter from "timered-counter/string-adapter/grapheme-splitter.js";
registerAdapter(GraphemeSplitterStringAdapter); // 注册内置的 grapheme-splitter 适配器
setStringAdapter('grapheme-splitter'); // 设置使用的适配器
```
:::
## 用法 {#usage}
你只需要更新数值,`TimeredCounter` 会自动处理剩下的事情。
下方这是一个简单的示例,`TimeredCounter` 会自动响应数字的变化,并且会自动处理数字的增减动画。
::: code-group
<<< @/components/GettingStartedDemo.vue#html{html} \[HTML]
<<< @/components/GettingStartedDemo.vue#js{js} \[JS]
<<< @/components/GettingStartedDemo.vue{vue} \[All]
:::
## 下一步 {#next}
* 想查看更多 `TimeredCounter` 的示例?请查看 [示例](./examples/simple-usage)。
* 要了解 `TimeredCounter` 的配置参数?请查看 [配置和API](../reference/api)。
* 要探索 `TimeredCounter` 样式和动画更多的可能性,例如实现[这样](./examples/logo)的效果?你可以从 [深入 TimeredCounter](./timered-counter-in-depth) 开始。
---
---
url: /zh/guide/examples/locale-usage.md
---
# 本地化(国际化) {#locale-usage}
TimeredCounter 对有必要的组件提供了本地化功能。
[timered-counter-number](#locale-number) 和 [timered-counter-datetime-duration](#locale-datetime-duration) 组件支持本地化,你可以通过 `locale` 属性来设置本地化的配置。
大多数情况下,你只需要将 `locale` 属性设置为 **语言代码**(如 `en`,`en-US`,`zh`,`zh-CN`)即可。
TimeredCounter 内部将调用 [Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) API 来处理本地化。
## 时间间隔本地化 {#locale-datetime-duration}
::: details 点击查看代码
::: code-group
<<< @/components/LocaleDatetimeDurationDemo.vue#html{html} \[HTML]
<<< @/components/LocaleDatetimeDurationDemo.vue#js{js} \[JS]
<<< @/components/LocaleDatetimeDurationDemo.vue{vue} \[All]
<<< @/components/LocaleSelect.vue{vue} \[LocaleSelect.vue]
:::
## 数字本地化 {#locale-number}
特别的,`timered-counter-number` 组件还需要设置 `locale-number` 属性。
* 你可以将其设置为 `true` ,这将使用默认配置启用数字本地化。
* 也可以设置为 [Intl.NumberFormat 支持的选项](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options)。
::: details 点击查看代码
::: code-group
<<< @/components/LocaleNumberDemo.vue#html{html} \[HTML]
<<< @/components/LocaleNumberDemo.vue#js{js} \[JS]
<<< @/components/LocaleNumberDemo.vue{vue} \[All]
<<< @/components/LocaleSelect.vue{vue} \[LocaleSelect.vue]
:::
---
---
url: /zh/guide/timered-counter-in-depth.md
---
# 深入 TimeredCounter {#timered-counter-in-depth}
## 结构 {#structure}
TimeredCounter 由 \,\,\ | 和 \ 组成。你可以在下方的示例的标注中看到这些部分。
其中 \ 是一个可选的部分。在下方示例中,它被用于显示时间(day,hour)单位。
### 层级关系 {#hierarchy}
以上方示例作为参考,TimeredCounter 的层级关系如下:
```
part -> digit -> cell
-> digit -> cell
-> suffix (day)
part -> digit -> cell
-> digit -> cell
-> suffix (hour)
```
## 用途 {#usage}
> 简单使用时(如[简单的滚动效果](./examples/simple-usage), [本地化](./examples/locale-usage)),大可不必关心 TimeredCounter 的实现细节。
>
> 但是,当我们需要自定义动画效果,例如(),或者需要自定义每个数位的样式时,了解 TimeredCounter 的结构是必不可少的。
为了提供足够的自由度来自定义动画效果和样式。你可以使用
1. `animationOptions` 设置精确到 的动画属性。
2. `cellStyle` 设置精确到 的样式属性。
### 设置动画属性 {#set-animation-options}
`animationOptions` 是 [`Element.animate(keyframes, options)`](https://developer.mozilla.org/en-US/docs/Web/API/Element/animate#options) 的第二个参数,你可以在这里设置动画的属性,比如 `duration`,`delay`,`easing` 等。
配置的形式可以有如下几种:
* 一个对象,包含你设置的配置项,将应用到所有 。
```js
{ duration: 0.5, delay: 0.1 }
```
* 一个一维数组,将应用到对应 中的所有 。
```js
[
{ duration: 0.5, delay: 0.1 }, // part 1
{ duration: 0.5, delay: 0.4 }, // part 2
...
]
```
* 一个二维数组,将应用到对应 中的对应 。
```js
[
[ // part 1
{ duration: 0.5, delay: 0.1 }, // digit 1
{ duration: 0.5, delay: 0.4 }, // digit 2
...
],
...
]
```
* 一个回调函数,接受一个对象,其中包含:
* `preprocessData`:一个二维数组,包含了每个 的测试结果。
* `data`:用于滚动的数据。包含了构造每个 滚动列表的数据。
* `direction`:滚动的方向。`up` 或 `down`。
* `value`:数值的新值和旧值。
函数的返回值可以是上述三种形式之一。
比如,在[延时示例](./examples/animated-usage#delay)中,在启用**延迟递增**后,对每个 的动画延时进行了设置,以实现递增的延时效果。
<<< @/components/AdvancedDelayDemo.vue#increaseDelay{16-18 js}
### 自定义样式 {#custom-style}
`cellStyle` 是个 `CSSProperties` ,你可以在这里设置 的样式。
配置的形式在 `animationOptions` 的基础上增加了一层:
* 一个三维数组,将应用到对应 中的对应 中的对应 。
```js
[
[
// part 1
[
// digit 1
{ color: "red" }, // cell 1
{ color: "blue" }, // cell 2
],
],
];
```
* 回调函数的形式与 `animationOptions` 相同。也可以返回三维数组。
---
---
url: /zh/guide/examples/simple-usage.md
---
# 简单的滚动效果 {#simple-usage}
TimeredCounter 提供了下列组件,他们用于滚动不同类型的数据:
* [timered-counter-number](#number):`number`,`bigint`
* [timered-counter-datetime-duration](#datetime):`Date`
* [timered-counter-string](#string):`string`
仅使用默认的配置,即可获得一个看起来不错的滚动效果。
::: tip
点击 切换 按钮,观察数值的改变。
:::
## 使数字滚动 {#number}
想像一下,现实生活中的水表,它会不断地滚动,显示当前的用水量。TimeredCounter 可以帮助你实现这样的效果。
::: details 点击查看代码
::: code-group
<<< @/components/BasicNumberDemo.vue#html{html} \[HTML]
<<< @/components/BasicNumberDemo.vue#js{js} \[JS]
<<< @/components/BasicNumberDemo.vue{vue} \[All]
:::
## 倒计时效果 {#datetime-duration}
我相信你已经见过很多的倒计时,但大部分的变化是生硬的,没有过渡。TimeredCounter 可以让你的倒计时效果更加平滑。
::: details 点击查看代码
::: code-group
<<< @/components/BasicDatetimeDurationDemo.vue#html{html} \[HTML]
<<< @/components/BasicDatetimeDurationDemo.vue#js{js} \[JS]
<<< @/components/BasicDatetimeDurationDemo.vue{vue} \[All]
:::
## 字符串也可以滚动 {#string}
看到[首页](/)上那个会动的标题了吗?在静态网页上,这样的效果会让你的页面更加生动。
::: tip
请注意,默认配置下最长支持 **14~15** 个字符。如果你需要更多的字符长度,请参阅[如何解除字符长度限制](../optional-dependencies.md#how-to-remove-character-length-limit)。
:::
::: details 点击查看代码
::: code-group
<<< @/components/BasicStringDemo.vue#html{html} \[HTML]
<<< @/components/BasicStringDemo.vue#js{js} \[JS]
<<< @/components/BasicStringDemo.vue{vue} \[All]
:::
## 下一步 {#next}
* 要了解如何设置语言敏感的数字格式,日期和时间格式,请查看[本地化](locale-usage.md)。
* 如果想自定义组件外观或过渡动画,请查看[自定义样式](styled-usage.md)和[自定义动画](animated-usage.md)。
---
---
url: /zh/guide/examples/animated-usage.md
---
# 自定义动画 {#animated-usage}
> 此章节假设你对 [CSS 动画](https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_animations) 或 [CSS 过渡](https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_transitions)有一定了解。
>
> 如果你不了解 CSS 动画或 CSS 过渡,建议先学习相关内容。
## 延时 {#delay}
::: details 点击查看代码
::: code-group
<<< @/components/AdvancedDelayDemo.vue#html{html} \[HTML]
<<< @/components/AdvancedDelayDemo.vue#js{js} \[JS]
<<< @/components/AdvancedDelayDemo.vue{vue} \[All]
:::
## 缓动 {#easing}
为了更容易观察缓动效果,可调整动画时长并调大了字体。
::: details 点击查看代码
::: code-group
<<< @/components/AdvancedEasingDemo.vue#html{html} \[HTML]
<<< @/components/AdvancedEasingDemo.vue#js{js} \[JS]
<<< @/components/AdvancedEasingDemo.vue{vue} \[All]
<<< @/components/EasingView.vue{vue} \[EasingView.vue]
:::
---
---
url: /zh/guide/examples/styled-usage.md
---
# 自定义样式 {#styled-usage}
### 自定义颜色 {#color}
> 为了更容易观察填充颜色变化,调大了字体。
::: details 点击查看代码
::: code-group
<<< @/components/ColorfulNumberDemo.vue#html{html} \[HTML]
<<< @/components/ColorfulNumberDemo.vue#js{js} \[JS]
<<< @/components/ColorfulNumberDemo.vue{vue} \[All]
:::
### 自定义字体 {#font}
可以直接通过设置 CSS 属性来自定义字体的各种属性。
::: details 点击查看代码
::: code-group
<<< @/components/PlayfulNumberDemo.vue#html{html} \[HTML]
<<< @/components/PlayfulNumberDemo.vue#js{js} \[JS]
<<< @/components/PlayfulNumberDemo.vue{vue} \[All]
<<< @/components/GoogleFontPicker.vue{vue} \[GoogleFontPicker.vue]
:::
---
---
url: /zh/guide/optional-dependencies.md
---
# 限制及如何解决 {#optional-dependencies}
## 字符长度限制 {#character-length-limit}
> TL;DR: [解决方案](#如何解除字符长度限制)。
[//]: # "你可能已经注意到了,在[安装](../guide/getting-started#前置准备)的时候,我们提到了两个可选依赖。"
`TimeredCounter` 实现原理是将字符串视为某个进制的数字,然后将其转换为十进制数字。这样做的目的是为了方便采样数字制作滚动列表。
这种方式在大多数情况下都是可行的,但是当数字太大或太小时,就会出现问题。
在 ECMA 规范中,当 `number < 10^-5 || number > 10^21` 时,数字将使用科学记数法表示[^1][^2]。
这样问题就来了,数字将使用科学记数法表示后会丢失部分精度。
```
1234567891012131415161
=> 1.2345678910121315e+21 // 丢失了后 6 位精度
```
由于实现方式的原因,这种情况在 `timered-counter-string` 上较为容易出现。
因为进制数基本上是字符串中不重复字符的个数,这将很容易得到一个超过 `10^21` 的数字。
类似的,当我们使用 `timered-counter-number` 时,如果数值小于 `10^-5`,数字也将使用科学记数法表示。
### 如何解除字符长度限制 {#how-to-remove-character-length-limit}
要解决这个问题,我们需要使用第三方高精度计算库,如 [decimal.js](https://mikemcl.github.io/decimal.js)。`TimeredCounter` 提供了两个适配器:
1. `BuildInNumberAdapter`(默认): 使用 `Number`。
[//]: # "2. `BuildInBigintAdapter`: 使用 `BigInt`,但**不支持小数**。"
2. `DecimalJsAdapter`: 使用 `decimal.js`,需要安装 [decimal.js](https://mikemcl.github.io/decimal.js)。
3. 当然,你可以实现自己的适配器,只需要实现 `NumberAdapter` 接口。
在下方示例中你可以切换适配器查看效果。
> `{{ Number.MAX_SAFE_INTEGER }}` 是 JavaScript 中能够精确表示的最大整数,大于该值时将会丢失精度。你可以尝试输入:
>
> 1. `{{ BigInt(Number.MAX_SAFE_INTEGER) + 1n }}`:{{ Number.MAX\_SAFE\_INTEGER }} **+ 1**
> 2. `{{ BigInt(Number.MAX_SAFE_INTEGER) + 10n }}`:{{ Number.MAX\_SAFE\_INTEGER }} **+ 10**
> 3. `{{ BigInt(Number.MAX_SAFE_INTEGER) + 100n }}`:{{ Number.MAX\_SAFE\_INTEGER }} **+ 100**
>
> 观察精度丢失的情况。
::: details 点击查看代码
::: code-group
<<< @/components/NumberAdapterDemo.vue{vue} \[NumberAdapterDemo.vue]
:::
## 支持 emoji 分词 {#support-emoji-segmentation}
对于一般的 `emoji`,我们可以直接使用默认的配置,但是对于一些**特殊**的 `emoji`,如 `👨👩👧👦`。他们被称为 `Emoji ZWJ Sequence`,是由多个 `emoji` 组合而成的。
这种情况下,难以将包含该 `emoji` 的字符串正确的识别。我们可以使用 [Intl.Segmenter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter) 或第三方库。
如 [grapheme-splitter](https://github.com/orling/grapheme-splitter)。`TimeredCounter` 提供了三个适配器:
1. `BuildInStringAdapter`(默认): 使用 `String.split("")` 分割字符串。
2. `IntlSegmenterAdapter`: 使用 `Intl.Segmenter`,需要浏览器支持。
3. `GraphemeSplitterAdapter`: 使用 `grapheme-splitter`。需要安装 [grapheme-splitter](https://github.com/orling/grapheme-splitter)
在下方示例中你可以切换适配器查看效果。
> 你可以尝试输入下列字符查看效果。
>
> * `⌚`:基础 emoji
> * `↔️`:文本字符渲染为 emoji
> * `👩`:可修饰的基础 emoji
> * `👩🏿`:可修饰的基础 emoji + emoji 修饰符
> * `🧑💻`:emoji 组合序列
::: details 点击查看代码
::: code-group
<<< @/components/StringAdapterDemo.vue{vue} \[StringAdapterDemo.vue]
:::
[^1]: https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-numeric-types-number-tostring
[^2]: https://medium.com/@anna7/large-numbers-in-js-4feb6269d29b