statistic —— 統計數值
Ce contenu n’est pas encore disponible dans votre langue.
統計數值元件展示「關鍵數字」:日活、營收、完成率。它的核心風險不是版面配置而是精度:Number(12345678901234567890).toFixed(2) 在 JS 裡會得到錯誤結果(超出安全整數),(0.1).toFixed 類別的四捨五入也有浮點陷阱。core/statistic 的 formatStatisticValue 把這些坑在共享層一次性填掉,三端共用。
- 各端實作
LhStatistic:儀表板數字、報表摘要、完成度展示。 - 需要把任意數值按「固定小數位 + 千位分隔」格式化的場景,即使不用元件也可以直接調
formatStatisticValue。 - 不該用它:貨幣符號、單位換算、時區格式化——這些是業務層的事;日期格式化用
core/shared/date。
import { formatStatisticValue, getStatisticClassNames } from '@lh-ui/share/core/statistic'import type { LhStatisticState } from '@lh-ui/share/core/statistic'formatStatisticValue 的三條精度防線:
- 非法輸入不拋錯:NaN / Infinity 原樣傳回
String(value),不試圖格式化「不是數的東西」。 - precision 淨化:
toFixed(101)會拋 RangeError,這裡先經shared/sanitize的safePrecision淨化到[0, 100]整數。這條防線與input-number共用(見 input-number)。 - 超大整數走字串路徑:整數部分超過
Number.MAX_SAFE_INTEGER時,全程不經過 Number 轉換——四捨五入用字串十進位進位(內部incrementDigits),分組用字串切片(formatBigString)。這是唯一能保證99999999999999999999格式化正確的方式。
| 函式 | 簽名 | 傳回 | 作用 |
|---|---|---|---|
formatStatisticValue |
(value: number | string, state: Pick<LhStatisticState, 'precision' | 'separator'>) => string |
格式化字串 | 精度 + 千位分隔 |
getStatisticClassNames |
(prefixCls?: string) => string[] |
類別名陣列 | 容器類,可換前綴 |
行為細節:
| 輸入 | 輸出 | 路徑 |
|---|---|---|
1234567.891, { precision: 2, separator: ',' } |
'1,234,567.89' |
toFixed + 分組 |
1234567.8, { precision: 0, separator: '' } |
'1234568' |
無分隔 |
'99999999999999999999', { precision: 0, separator: ',' } |
'99,999,999,999,999,999,999' |
字串路徑 |
NaN, 任意 |
'NaN' |
原樣傳回 |
'abc', 任意 |
'abc' |
Number('abc') 為 NaN |
分隔符只用於整數分組,小數點固定為 .(各端展示時如需本地化小數點,在 UI 層替換)。
export interface LhStatisticState { precision: number // 小數位數(經 safePrecision 淨化到 [0, 100]) separator: string // 千位分隔符,空串表示不分組}core/statistic 不輸出 aria 屬性包。統計數值的無障礙要點在 UI 層:
- 數字本身用普通文字即可被讀屏,但千位分隔逗號會被讀成「逗號」(如「1,234,567」讀成「一逗號二三四…」)。應當給整個數值塊提供
aria-label,用語言化的表述(「一百二十三萬四千五百六十七」或「1 2 3 4 5 6 7 」逐位)。 - 數值變化時的動畫(捲動到目標值)是純視覺,不承載資訊;若動畫中數值不可讀,期間應保持舊值的 aria-label 直到落定。
import { formatStatisticValue } from '@lh-ui/share/core/statistic'
formatStatisticValue(9876543.21, { precision: 1, separator: ' ' })// '9 876 543.2'
formatStatisticValue(0.1 + 0.2, { precision: 2, separator: '' })// '0.30' (而不是 0.30000000000000004 的一部分)
formatStatisticValue('12345678901234567890', { precision: 0, separator: ',' })// '12,345,678,901,234,567,890'<!-- Vue3 --><div :class="getStatisticClassNames()"> <span v-if="prefix" class="lh-statistic__prefix">{{ prefix }}</span> <span class="lh-statistic__content"> <span class="lh-statistic__title">{{ title }}</span> <span class="lh-statistic__value" :aria-label="ariaLabel"> {{ formatStatisticValue(value, { precision, separator }) }} </span> </span> <span v-if="suffix" class="lh-statistic__suffix">{{ suffix }}</span></div>// Reactconst text = formatStatisticValue(value, { precision, separator })return ( <div className="lh-statistic"> <span className="lh-statistic__content"> <span className="lh-statistic__title">{title}</span> <span className="lh-statistic__value" aria-label={spoken}>{text}</span> </span> </div>)// uniapp:純字串輸出,無端差異;動畫各端用自帶的捲動方案| 類別名 | 語義 |
|---|---|
.lh-statistic |
基礎類:版面配置 |
.lh-statistic__title |
標題(次級文字色、小字級) |
.lh-statistic__content |
內容區(標題 + 數值縱向排列) |
.lh-statistic__value |
數值(主文字色、大字級、等寬數字 font-variant-numeric: tabular-nums) |
.lh-statistic__prefix / .lh-statistic__suffix |
前後綴(如 ¥、%) |
數值字型走 --lh-font-family-numeric 令牌(若有),保證數字寬度對齊。
- precision 上限 100:超出會被
safePrecision截斷而非拋錯;負數 precision 歸 0。 - 字串輸入的語義:
formatStatisticValue('123', ...)會先嘗試Number('123'),成功則走數字路徑;'abc'才原樣傳回。超大整數字串必須以字串傳入——傳數字字面量99999999999999999999在 JS 原始碼層就已經丟精度了,core 無法救回。 - 不要在 UI 層自己寫千位分隔的
toLocaleString:它受執行時 locale 影響,三端可能不一致;統一用formatStatisticValue。 getStatisticClassNames的prefixCls參數允許換前綴(預設lh-statistic),用於某些端需要與既有類別名共存的場景。
@lh-ui/share/core/statistic → formatStatisticValue( )返回值
(填好参数后点运行)Copyright © 2024-2026 FengMo WenXue