Skip to content

Commit eed86cb

Browse files
committed
feat: enhance mixed char demo, fix full-width layout, remove old demo
1 parent 919d53d commit eed86cb

13 files changed

Lines changed: 446 additions & 120 deletions

File tree

README.md

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<h1 align="center">Smart Ticker</h1>
77

88
<p align="center">
9-
高性能智能文本差异滚动组件,基于 Levenshtein diff 算法,支持多字符集,适用于React/Vue,<a href="https://tombcato.github.io/smart-ticker/">官网演示></a>
9+
高性能智能文本差异滚动组件,支持中英、数字、字母、符号、Emoji等多种字符集,基于 Levenshtein diff 算法,适用于React/Vue,<a href="https://tombcato.github.io/smart-ticker/">官网演示></a>
1010
</p>
1111

1212
<p align="center">
@@ -16,6 +16,9 @@
1616
<p align="center">
1717
<img src="./smartticker.gif" alt="Demo" width="600" />
1818
</p>
19+
<p align="center">
20+
<img src="./smartticker2.gif" alt="Demo" width="600" />
21+
</p>
1922

2023
<p align="center">
2124
<img src="https://img.shields.io/badge/React-18+-61DAFB?logo=react" alt="React" />
@@ -26,14 +29,11 @@
2629

2730

2831
## ✨ 特性
29-
30-
- **智能差异动画** - 只有变化的字符会滚动,相同的字符保持静止
31-
- **平滑中断** - 动画过程中值变化时,从当前位置无缝衔接到新目标
32-
- **多种缓动曲线** - 支持 `linear``easeInOut``bounce` 等多种动画效果
33-
- **字符宽度可调** - 通过 `charWidth` 属性控制字符间距
34-
- **多字符集支持** - 支持数字、字母、符号等多种字符集,可混合使用
35-
- **双框架支持** - 提供 React 组件和 Vue 组件
36-
- **高性能** - 使用 `requestAnimationFrame``React.memo` 优化渲染
32+
| | |
33+
| :--- | :--- |
34+
| **🌏 多字符集支持**<br>支持中英、数字、Emoji等混合滚动,基于 Unicode 宽度自动调整间距 | **🧠 智能差异动画**<br>Levenshtein 算法计算最小变更路径,相同的字符保持静止 |
35+
| **⚡ 平滑中断**<br>动画过程中值突变时,从当前动态位置无缝流向新目标 | **📈 丰富动效**<br>内置 `linear`, `bounce`, `easeInOut` 等缓动,支持 `charWidth` 微调 |
36+
| **🦄 双框架支持**<br>提供 React (Hooks) 和 Vue 3 (Composition) 组件,API 统一 | **🚀 极致性能**<br>基于 `RAF` 驱动,无多余 DOM 操作,适合高频数据流场景 |
3737

3838
## 📦 安装
3939

@@ -155,8 +155,32 @@ const price = ref('73.18');
155155
import { TickerUtils } from './components/Ticker';
156156

157157
TickerUtils.provideNumberList() // '0123456789'
158-
TickerUtils.provideAlphabeticalList() // 'abcdefghijklmnopqrstuvwxyz'
159-
TickerUtils.provideHexadecimalList() // '0123456789ABCDEF'
158+
TickerUtils.provideAlphabeticalList() // 'abc...zABC...Z'
159+
160+
### 🧩 字符集配置详解
161+
162+
`characterLists` 是控制 Ticker 动画逻辑的核心配置。它接受一个字符串数组,数组的每一项代表一组**“可以互相滚动”**的字符。
163+
164+
**基本规则:**
165+
1. **同组滚动**:如果旧字符和新字符在同一个字符串中(例如 `0``9``'0123456789'` 中),它们会产生滚动动画。
166+
2. **跨组替换**:如果它们不在同一组(例如 `a``1`),或者任何一个字符不在配置列表中(例如汉字),它们会原地切换(Switch),不会产生滚动。
167+
168+
**配置技巧:**
169+
170+
* **默认全字母**`TickerUtils.provideAlphabeticalList()` 默认包含 `a-z``A-Z`。如果你希望大小写之间可以滚动(如 `a` -> `A`),使用它即可。
171+
* **由于物理隔离**:如果你不希望小写字母滚动变成大写字母(希望它们直接切换),请将它们配置为两个独立的字符串,例如 `['abc...', 'ABC...']`
172+
173+
**示例:**
174+
175+
```javascript
176+
// 场景:数字、字母(大小写隔离)、符号
177+
characterLists={[
178+
'abcdefghijklmnopqrstuvwxyz', // 小写组
179+
'ABCDEFGHIJKLMNOPQRSTUVWXYZ', // 大写组
180+
'0123456789', // 数字组
181+
'.,!@#$%^&*' // 符号组
182+
]}
183+
```
160184
```
161185

162186
## 💻 运行演示

README_EN.md

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55

66
<h1 align="center">Smart Ticker</h1>
77

8-
<p align="center">
9-
High-performance smart text ticker component based on Levenshtein diff algorithm. Supports multiple charsets, works with React/Vue. <a href="https://tombcato.github.io/smart-ticker/">Live Demo ></a>
10-
</p>
8+
High-performance smart text ticker component based on Levenshtein diff algorithm. Supports CJK, numbers, letters, emojis, and mixed charsets. <a href="https://tombcato.github.io/smart-ticker/">Live Demo ></a>
119

1210
<p align="center">
1311
<a href="./README.md">简体中文</a> | <strong>English</strong>
@@ -16,6 +14,9 @@
1614
<p align="center">
1715
<img src="./smartticker.gif" alt="Demo" width="600" />
1816
</p>
17+
<p align="center">
18+
<img src="./smartticker2.gif" alt="Demo" width="600" />
19+
</p>
1920

2021
<p align="center">
2122
<img src="https://img.shields.io/badge/React-18+-61DAFB?logo=react" alt="React" />
@@ -25,15 +26,11 @@
2526
</p>
2627

2728

28-
## ✨ Features
29-
30-
- **Smart Diff Animation** - Only changed characters scroll, identical ones remain static.
31-
- **Smooth Interruption** - Seamlessly transitions to new targets if value changes during animation.
32-
- **Custom Easing** - Supports `linear`, `easeInOut`, `bounce` and more.
33-
- **Adjustable Char Width** - Control character spacing via `charWidth` prop.
34-
- **Multi-Charset** - Supports numbers, letters, symbols, and mixed usage.
35-
- **Dual Framework Support** - Provides both React and Vue components.
36-
- **High Performance** - Optimized with `requestAnimationFrame` and `React.memo`.
29+
| | |
30+
| :--- | :--- |
31+
| **🌏 Multi-Charset Support**<br>Supports CJK, Numbers, Emojis, and mixed text rolling. Auto-adjusts spacing based on Unicode width. | **🧠 Smart Diff Animation**<br>Uses Levenshtein algorithm to find the shortest change path; identical characters remain static. |
32+
| **⚡ Smooth Interruption**<br>Seamlessly transitions to new targets if the value changes dynamically during animation. | **📈 Rich Motion**<br>Built-in `linear`, `bounce`, `easeInOut` easings. Supports `charWidth` for fine-tuning. |
33+
| **🦄 Dual Framework**<br>Provides both React (Hooks) and Vue 3 (Composition) components with a unified API. | **🚀 High Performance**<br>Powered by `RAF`, removing DOM overhead, optimized for high-frequency data streams. |
3734

3835
## 📦 Installation
3936

@@ -155,8 +152,31 @@ The component uses the system monospace stack by default. To use a custom font (
155152
import { TickerUtils } from './components/Ticker';
156153

157154
TickerUtils.provideNumberList() // '0123456789'
158-
TickerUtils.provideAlphabeticalList() // 'abcdefghijklmnopqrstuvwxyz'
159-
TickerUtils.provideHexadecimalList() // '0123456789ABCDEF'
155+
TickerUtils.provideAlphabeticalList() // 'abc...zABC...Z'
156+
157+
### 🧩 Character Configuration
158+
159+
`characterLists` controls the core animation logic. It accepts an array of strings, where each string represents a group of characters that can **scroll into each other**.
160+
161+
**Rules:**
162+
1. **Scroll**: If both the old and new characters belong to the same group string (e.g., `0` to `9` in `'0123456789'`), they will scroll.
163+
2. **Switch**: If they are in different groups, or if a character is not in any list (e.g., Chinese characters), they will switch instantly without scrolling.
164+
165+
**Configuration Tips:**
166+
167+
* `TickerUtils.provideAlphabeticalList()` includes both `a-z` and `A-Z`.
168+
* To prevent scrolling between cases (e.g., `a` -> `A`), provide them as separate strings: `['abc...', 'ABC...']`.
169+
170+
**Example:**
171+
172+
```javascript
173+
characterLists={[
174+
'abcdefghijklmnopqrstuvwxyz', // Lowercase group
175+
'ABCDEFGHIJKLMNOPQRSTUVWXYZ', // Uppercase group
176+
'0123456789', // Number group
177+
'.,!@#$%^&*' // Symbol group
178+
]}
179+
```
160180
```
161181

162182
## 💻 Running Demos

examples/react-demo/src/App.tsx

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,59 @@
11
import { useState, useEffect } from 'react'
2-
import { Ticker } from '@tombcato/smart-ticker'
2+
import { Ticker, TickerUtils } from '@tombcato/smart-ticker'
33
import '@tombcato/smart-ticker/style.css'
44

55
type EasingType = 'linear' | 'easeInOut' | 'bounce'
6+
type DemoMode = 'price' | 'text'
67

78
function App() {
8-
const [value, setValue] = useState(173.50)
9+
const [mode, setMode] = useState<DemoMode>('price')
10+
const [value, setValue] = useState<string | number>(173.50)
911
const [charWidth, setCharWidth] = useState(1)
1012
const [duration, setDuration] = useState(800)
1113
const [easing, setEasing] = useState<EasingType>('easeInOut')
1214

1315
useEffect(() => {
14-
const prices = [73.18, 76.58, 173.50, 9.10]
15-
let idx = 0
16-
const timer = setInterval(() => {
17-
idx = (idx + 1) % prices.length
18-
setValue(prices[idx])
19-
}, 2000)
16+
let timer: number
17+
18+
if (mode === 'price') {
19+
const prices = [73.18, 76.58, 173.50, 9.10]
20+
let idx = 0
21+
setValue(prices[0])
22+
timer = setInterval(() => {
23+
idx = (idx + 1) % prices.length
24+
setValue(prices[idx])
25+
}, 2000)
26+
} else {
27+
const words = [
28+
'Smart Ticker',
29+
'Small Diff',
30+
'哈基米 Dif@#$',
31+
'硅基生命 %@#$',
32+
'宇宙生命 Smart',
33+
]
34+
let idx = 0
35+
setValue(words[0])
36+
timer = setInterval(() => {
37+
idx = (idx + 1) % words.length
38+
setValue(words[idx])
39+
}, 2000)
40+
}
41+
2042
return () => clearInterval(timer)
21-
}, [])
43+
}, [mode])
44+
45+
// Determine character lists based on mode
46+
const currentCharacterLists = mode === 'price'
47+
? ['0123456789.,']
48+
: [
49+
TickerUtils.provideAlphabeticalList(),
50+
TickerUtils.provideAlphabeticalList().toUpperCase(),
51+
TickerUtils.provideNumberList(),
52+
' .%v-@#$'
53+
]
54+
55+
// Determine display value
56+
const displayValue = mode === 'price' ? Number(value).toFixed(2) : String(value)
2257

2358
return (
2459
<div className="app-container">
@@ -31,19 +66,28 @@ function App() {
3166
</header>
3267

3368
<div className="ticker-display">
34-
<span className="currency-symbol">$</span>
69+
{mode === 'price' && <span className="currency-symbol">$</span>}
3570
<div className="ticker-main">
3671
<Ticker
37-
value={value.toFixed(2)}
72+
value={displayValue}
3873
duration={duration}
3974
easing={easing}
4075
charWidth={charWidth}
41-
characterLists={['0123456789.,']}
76+
characterLists={currentCharacterLists}
4277
/>
4378
</div>
4479
</div>
4580

4681
<div className="controls">
82+
{/* 模式切换 */}
83+
<div className="control-group">
84+
<div className="label">演示模式</div>
85+
<div className="options">
86+
<button className={mode === 'price' ? 'active' : ''} onClick={() => setMode('price')}>数字</button>
87+
<button className={mode === 'text' ? 'active' : ''} onClick={() => setMode('text')}>文本</button>
88+
</div>
89+
</div>
90+
4791
{/* 字符宽度控制 */}
4892
<div className="control-group">
4993
<div className="label">字符宽度</div>
@@ -99,15 +143,15 @@ function App() {
99143

100144
<footer className="code-section">
101145
<h2>💻 使用代码</h2>
102-
<pre><code>{`import { Ticker } from '@tombcato/smart-ticker'
146+
<pre><code>{`import { Ticker, TickerUtils } from '@tombcato/smart-ticker'
103147
import '@tombcato/smart-ticker/style.css'
104148
105149
<Ticker
106-
value="${value.toFixed(2)}"
150+
value="${displayValue}"
107151
duration={${duration}}
108152
easing="${easing}"
109153
charWidth={${charWidth}}
110-
characterLists={['0123456789.,']}
154+
characterLists={${mode === 'price' ? "['0123456789.,']" : "[TickerUtils.provideAlphabeticalList()]"}}
111155
/>`}</code></pre>
112156
</footer>
113157
</div>

0 commit comments

Comments
 (0)