Перейти к содержимому

statistic —— Статистические значения

Компонент статистических значений показывает «ключевые цифры»: дневная активность, выручка, процент выполнения. Его главный риск — не раскладка, а точность: Number(12345678901234567890).toFixed(2) в JS даёт неверный результат (превышение безопасного целого), а в (0.1).toFixed-подобном округлении таятся ловушки плавающей точки. formatStatisticValue из core/statistic закрывает эти ловушки в общем слое один раз для всех платформ.

  • При реализации 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, поэтому здесь precision сначала проходит через safePrecision из shared/sanitize и приводится к целому в [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: оно зависит от локали во время выполнения, и на разных платформах результаты могут не совпадать; используйте единый formatStatisticValue.
  • Параметр prefixCls у getStatisticClassNames позволяет заменить префикс (по умолчанию lh-statistic) — для сценариев, когда платформе нужно сосуществовать с существующими классами.
@lh-ui/share/core/statistic → formatStatisticValue( )
返回值
(填好参数后点运行)

Copyright © 2024-2026 FengMo WenXue