mirror of
https://github.com/tabler/tabler.git
synced 2026-01-25 04:16:36 +00:00
feat: implement Countup component with initialization, update, and disposal methods
This commit is contained in:
@@ -1,10 +1,56 @@
|
||||
const countupElements: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>('[data-countup]')
|
||||
import { CountUp } from 'countup.js'
|
||||
|
||||
if (countupElements.length) {
|
||||
countupElements.forEach(function (element: HTMLElement) {
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Tabler countup.js
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
|
||||
const NAME = 'countup'
|
||||
const DATA_KEY = `tblr.${NAME}`
|
||||
|
||||
const SELECTOR_DATA_COUNTUP = '[data-countup]'
|
||||
|
||||
/**
|
||||
* Class definition
|
||||
*/
|
||||
|
||||
class Countup {
|
||||
private element: HTMLElement
|
||||
private countUpInstance: CountUp | null = null
|
||||
private initialized: boolean = false
|
||||
private options: Record<string, any> = {}
|
||||
|
||||
constructor(element: HTMLElement) {
|
||||
this.element = element
|
||||
}
|
||||
|
||||
// Getters
|
||||
static get NAME() {
|
||||
return NAME
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
}
|
||||
|
||||
// Public
|
||||
/**
|
||||
* Initialize countup on the element
|
||||
*/
|
||||
init(): void {
|
||||
if (this.initialized) {
|
||||
return
|
||||
}
|
||||
|
||||
// Parse options from data attribute
|
||||
let options: Record<string, any> = {}
|
||||
try {
|
||||
const dataOptions = element.getAttribute('data-countup') ? JSON.parse(element.getAttribute('data-countup')!) : {}
|
||||
const dataOptions = this.element.getAttribute('data-countup') ? JSON.parse(this.element.getAttribute('data-countup')!) : {}
|
||||
options = Object.assign(
|
||||
{
|
||||
enableScrollSpy: true,
|
||||
@@ -15,13 +61,79 @@ if (countupElements.length) {
|
||||
// ignore invalid JSON
|
||||
}
|
||||
|
||||
const value = parseInt(element.innerHTML, 10)
|
||||
this.options = options
|
||||
|
||||
if (window.countUp && window.countUp.CountUp) {
|
||||
const countUp = new window.countUp.CountUp(element, value, options)
|
||||
if (!countUp.error) {
|
||||
countUp.start()
|
||||
const value = parseInt(this.element.innerHTML, 10)
|
||||
|
||||
if (!isNaN(value)) {
|
||||
this.countUpInstance = new CountUp(this.element, value, options)
|
||||
if (!this.countUpInstance.error) {
|
||||
this.countUpInstance.start()
|
||||
this.initialized = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Update countup (restart animation)
|
||||
*/
|
||||
update(): void {
|
||||
if (!this.initialized || !this.countUpInstance) {
|
||||
return
|
||||
}
|
||||
|
||||
const value = parseInt(this.element.innerHTML, 10)
|
||||
if (!isNaN(value)) {
|
||||
this.countUpInstance = new CountUp(this.element, value, this.options)
|
||||
if (!this.countUpInstance.error) {
|
||||
this.countUpInstance.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy countup instance
|
||||
*/
|
||||
dispose(): void {
|
||||
if (!this.initialized) {
|
||||
return
|
||||
}
|
||||
|
||||
// CountUp doesn't have a destroy method, so we just reset state
|
||||
this.countUpInstance = null
|
||||
this.initialized = false
|
||||
}
|
||||
|
||||
// Static
|
||||
/**
|
||||
* Get instance from element
|
||||
*/
|
||||
static getInstance(element: HTMLElement): Countup | null {
|
||||
return elementMap.get(element) || null
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create instance
|
||||
*/
|
||||
static getOrCreateInstance(element: HTMLElement): Countup {
|
||||
return this.getInstance(element) || new this(element)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instance storage
|
||||
*/
|
||||
const elementMap = new WeakMap<HTMLElement, Countup>()
|
||||
|
||||
/**
|
||||
* Data API implementation
|
||||
*/
|
||||
const countupTriggerList: HTMLElement[] = [].slice.call(document.querySelectorAll<HTMLElement>(SELECTOR_DATA_COUNTUP))
|
||||
countupTriggerList.map(function (countupTriggerEl: HTMLElement) {
|
||||
const instance = Countup.getOrCreateInstance(countupTriggerEl)
|
||||
elementMap.set(countupTriggerEl, instance)
|
||||
instance.init()
|
||||
return instance
|
||||
})
|
||||
|
||||
export default Countup
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import './src/autosize'
|
||||
import './src/countup'
|
||||
import './src/input-mask'
|
||||
import './src/dropdown'
|
||||
import './src/tooltip'
|
||||
import './src/popover'
|
||||
import './src/switch-icon'
|
||||
import './src/tab'
|
||||
import './src/toast'
|
||||
import './src/sortable'
|
||||
@@ -18,6 +15,7 @@ export { Alert, Button, Carousel, Collapse, Dropdown, Modal, Offcanvas, Popover,
|
||||
// Export custom Tabler components
|
||||
export { default as Autosize } from './src/autosize'
|
||||
export { default as SwitchIcon } from './src/switch-icon'
|
||||
export { default as Countup } from './src/countup'
|
||||
|
||||
// Re-export everything as namespace for backward compatibility
|
||||
export * as bootstrap from 'bootstrap'
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
---
|
||||
title: Countup
|
||||
summary: A countup element is used to display numerical data in an interesting way and make the interface more interactive.
|
||||
docs-libs: countup
|
||||
description: Display numbers dynamically with countups.
|
||||
---
|
||||
|
||||
The countup component is used to display numbers dynamically. It is a great way to make the interface more interactive and engaging. The countup component is a simple and easy way to animate numbers in your application.
|
||||
|
||||
To be able to use the countup in your application you will need to install the countup.js dependency with `npm install countup.js`.
|
||||
The countup component is built into Tabler and works similar to Bootstrap components. It animates numbers dynamically, making the interface more interactive and engaging.
|
||||
|
||||
For more advanced features of countups, see the demo on the [countUp.js website](https://inorganik.github.io/countUp.js/).
|
||||
|
||||
## Basic usage
|
||||
|
||||
To create a countup, add `data-countup` to any HTML text tag and specify the number which is to be reached. The animation will be triggered as soon as the number enters the viewport.
|
||||
The easiest way to use countup is through the Data API. Add the `data-countup` attribute to any HTML text element and specify the number which is to be reached. The animation will be triggered as soon as the number enters the viewport.
|
||||
|
||||
```html
|
||||
<h1 data-countup>30000</h1>
|
||||
@@ -120,3 +117,64 @@ Set the countup suffix using `suffix` and specifying the suffix you want to add,
|
||||
<h1 data-countup='{"suffix":"‰"}'>300</h1>
|
||||
{%- endcapture %}
|
||||
{% include "docs/example.html" html=html vertical separated %}
|
||||
|
||||
## Usage
|
||||
|
||||
### Via data attributes
|
||||
|
||||
Add `data-countup` to any HTML text element to automatically initialize countup. You can pass options as JSON:
|
||||
|
||||
```html
|
||||
<h1 data-countup>30000</h1>
|
||||
<h1 data-countup='{"duration":4,"prefix":"$"}'>30000</h1>
|
||||
```
|
||||
|
||||
### Via JavaScript
|
||||
|
||||
Initialize countup programmatically using the `Countup` class:
|
||||
|
||||
```javascript
|
||||
import { Countup } from '@tabler/core'
|
||||
|
||||
// Get or create instance
|
||||
const element = document.querySelector('[data-countup]')
|
||||
const countup = Countup.getOrCreateInstance(element)
|
||||
countup.init()
|
||||
```
|
||||
|
||||
### Methods
|
||||
|
||||
| Method | Description |
|
||||
| --- | --- |
|
||||
| `init()` | Initialize countup on the element. |
|
||||
| `update()` | Update countup when the target value changes programmatically. |
|
||||
| `dispose()` | Destroy countup instance. |
|
||||
| `getInstance(element)` | *Static* method which allows you to get the countup instance associated with a DOM element. |
|
||||
| `getOrCreateInstance(element)` | *Static* method which allows you to get the countup instance associated with a DOM element, or create a new one in case it wasn't initialized. |
|
||||
|
||||
#### Example: Update after value change
|
||||
|
||||
```javascript
|
||||
import { Countup } from '@tabler/core'
|
||||
|
||||
const element = document.querySelector('[data-countup]')
|
||||
const countup = Countup.getOrCreateInstance(element)
|
||||
countup.init()
|
||||
|
||||
// Later, when the target value changes programmatically
|
||||
element.innerHTML = '50000'
|
||||
countup.update()
|
||||
```
|
||||
|
||||
#### Example: Get existing instance
|
||||
|
||||
```javascript
|
||||
import { Countup } from '@tabler/core'
|
||||
|
||||
const element = document.querySelector('[data-countup]')
|
||||
const countup = Countup.getInstance(element)
|
||||
|
||||
if (countup) {
|
||||
countup.update()
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user