Statistic 统计数值
展示一个突出的数字:标题、数值、前后缀与精度,数值变化时可选滚动过渡。
基础用法
<SrStatistic title="本月订单" :value="1234.5" suffix="单" />
<SrStatistic title="总用户" :value="1234567" />
<SrStatistic title="账户余额" :value="8900.5" prefix="¥" :precision="2" />
<SrStatistic title="转化率" :value="0.8934" suffix="%" :precision="1" />精度不传时从数值本身推断——传 3.14 就显示两位,不必再写一遍 :precision="2"。显式传入时才按它四舍五入。
前后缀是独立的元素,不拼进数值文本:拼进去的话它们会跟着数字一起变化、 一起参与等宽对齐,而 ¥、% 通常需要更小的字号与更弱的颜色。
滚动过渡
<SrStatistic title="累计访问量" :value="8848" animated suffix="次" />animated 开启后,数值变化时滚动过渡。
为什么默认关闭
若首次挂载就从 0 滚起,服务端渲染输出的终值与客户端首帧会对不上, 数字会闪一下。
需要进场滚动时,由宿主把初值设为 0、挂载后再改成目标值—— 这样动画统一由「值变化」触发,SSR 与首帧始终一致:
<script setup>
import { onMounted, ref } from 'vue'
const count = ref(0)
onMounted(() => {
count.value = 8848
})
</script>
<template>
<SrStatistic title="累计访问量" :value="count" animated />
</template>两个细节
最后一帧会显式写入目标值。 缓动到 1 时理论上恰好等于目标, 但浮点相乘未必——不显式对齐会留下 8847.999999 这样的尾数。
动画期间精度取自目标值并固定,不是每帧从插值结果推断—— 后者会让小数位数忽多忽少、文本宽度剧烈抖动。
尺寸与加载态
<SrStatistic size="sm" title="小" :value="12345" suffix="单" />
<SrStatistic size="lg" title="大" :value="12345" suffix="单" />
<SrStatistic title="加载中" :value="12345" loading />加载态保留标题、只把数值换成灰块,而不是整块留白—— 数据到位前后位置稳定,不会发生跳动。灰块宽度用 em 相对当前字号, 随 size 自动缩放。
格式化
<SrStatistic title="大数字分组" :value="1234567890" suffix="元" />
<SrStatistic :value="1234567.891" :precision="2" group-separator="." decimal-separator="," />
<SrStatistic :value="1234567" group-separator="" />分隔符可自定义,刻意不用 toLocaleString:它按运行环境的区域设置 决定分隔符,同一份代码在不同用户的浏览器上会显示出不同结果。 这类展示格式通常由产品定义,不该随系统语言漂移。
与数字输入框共用同一套舍入
精度走的是 SrInputNumber 里同一个 roundTo。浮点舍入只有一套正确写法, 两处若各写各的,迟早出现「输入框里是 1.01、统计卡上显示 1.00」这种自相矛盾。
超大整数
value 允许传字符串,用于超出安全整数范围的值。
<!-- ✅ 末位仍是 3 -->
<SrStatistic :value="'9007199254740993'" />
<!-- ❌ Number() 一转,末位变成 2 -->
<SrStatistic :value="Number('9007199254740993')" />看上面两个的差别:走字符串路径分组后末位仍是 3; 而经 Number() 一转就成了 9007199254740992,末位变成 2—— 丢一位且悄无声息。
这类值本来是标识符(雪花号、订单号)而非可运算的量, 字符串走「原样分组」路径、完全不参与运算。只认 -?\d+(\.\d+)? 这种最简单的形态,科学计数法之类一律原样返回。
自定义格式化
<script setup>
const toWan = (value) => (value / 10000).toFixed(2) + ' 万'
</script>
<template>
<SrStatistic title="缩写为万" :value="2847392" :formatter="toWan" />
</template>formatter 接管全部格式化,此时不再有滚动动画——任意函数无法插值, 硬要对中间结果反复调用只会让数字乱跳。
Props
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
title | string | — | 标题,也可用 title 插槽 |
value | number | string | 0 | 数值;字符串用于超大整数 |
precision | number | 自动推断 | 小数位数 |
prefix / suffix | string | — | 前缀 / 后缀文本 |
groupSeparator | string | ',' | 千分位分隔符,空串表示不分组 |
decimalSeparator | string | '.' | 小数分隔符 |
formatter | (value: number) => string | — | 自定义格式化,接管全部格式化且关闭动画 |
animated | boolean | false | 数值变化时滚动过渡 |
duration | number | 600 | 滚动时长(毫秒) |
size | 'sm' | 'md' | 'lg' | 'md' | 尺寸 |
loading | boolean | false | 是否显示加载骨架 |
插槽
| 名称 | 说明 |
|---|---|
title | 自定义标题 |
prefix / suffix | 自定义前后缀(可放图标而非纯文本) |
无障碍
- 数字用了
font-variant-numeric: tabular-nums:这对统计组件不是锦上添花 而是必需品——动画每帧都在改数字,字形宽度若随内容变化 (1明显比8窄),整个数字块会左右抽动 - 动画在
prefers-reduced-motion下直接落位、不做任何过渡; 加载骨架的微光同样停掉,但保留灰块(它是加载态唯一的可见信号, 藏了就什么都没有了)