コンテンツにスキップ

statistic —— 統計數值

このコンテンツはまだ日本語訳がありません。

統計數值元件展示「關鍵數字」:日活、營收、完成率。它的核心風險不是版面配置而是精度: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 的三條精度防線:

  1. 非法輸入不拋錯:NaN / Infinity 原樣傳回 String(value),不試圖格式化「不是數的東西」。
  2. precision 淨化:toFixed(101) 會拋 RangeError,這裡先經 shared/sanitize 的 safePrecision 淨化到 [0, 100] 整數。這條防線與 input-number 共用(見 input-number)。
  3. 超大整數走字串路徑:整數部分超過 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>
// React
const 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