Ant Design Statistic 组件完全指南:统计数值、倒计时/正计时与语义化定制
导读:本文以 components/statistic/index.zh-CN.md 为骨架,系统讲解 Ant Design 中 Statistic(统计数值)组件的使用场景、完整 API、倒计时与正计时(Statistic.Timer)、语义化 DOM 与主题 Token 定制,并结合当前仓库源码解析数值格式化、计时刷新等底层实现,帮助你在数据看板、监控页、营销页中正确、高效地展示关键数字。
Statistic 是 Ant Design 数据展示组件族中的一员,专门用于突出展示单个或一组关键统计数字,例如用户量、成交额、完成率、剩余时间等。组件本身只负责“把数字好看地展示出来”,不承载任何数据请求逻辑,因此非常适合与大屏、Dashboard、Card、Descriptions 等布局自由组合。从当前仓库的目录结构看,Statistic 的完整实现位于 components/statistic,组件聚合入口在 index.tsx,其下挂载了 Statistic.Timer 与(已废弃的)Statistic.Countdown 两个子组件,与文档 index.zh-CN.md 描述的 API 一一对应。
何时使用 Statistic
官方文档明确了两种典型诉求:
- 当需要突出某个或某组数字时使用,例如“今日销售额”“在线人数”“QPS”等;
- 当需要展示带描述的统计类数据时使用,例如“完成率 98.3%”这类“描述 + 数值”的组合。
一句话:任何“标题 + 大号数字(可带单位、前后缀)”的展示需求,都是 Statistic 的用武之地。它本身不含图表、不含请求、不含交互逻辑,是纯展示型组件,这也是它能被嵌入 Card、Grid、Skeleton 等容器中自由组合的原因——从源码看,Statistic 在 loading 状态下直接复用了 Skeleton 组件来渲染占位骨架,见 Statistic.tsx。
基础用法与常见场景
文档下的代码演示(components/statistic/demo/ 目录)覆盖了 7 类典型场景,几乎可以当作组件的“最小用例集”来阅读。
基本:标题 + 数值 + 精度
basic.tsx 展示最基本的用法:一个 title 加一个 value 即可完成一次统计展示;数值精度通过 precision 控制:
import { Button, Col, Row, Statistic } from 'antd';
const App: React.FC = () => (
<Row gutter={16}>
<Col span={12}>
<Statistic title="Active Users" value={112893} />
</Col>
<Col span={12}>
<Statistic title="Account Balance (CNY)" value={112893} precision={2} />
<Button style={{ marginTop: 16 }} type="primary">Recharge</Button>
</Col>
<Col span={12}>
<Statistic title="Active Users" value={112893} loading />
</Col>
</Row>
);
export default App;
可以看到几个关键点:
value即数值内容,类型为string | number;precision={2}会将数值格式化为保留两位小数(不足补 0,超出截断,处理逻辑见后文源码分析);loading置为true时数值区域会以骨架屏呈现(该属性自 4.8.0 起提供)。
单位与前后缀:prefix / suffix
unit.tsx 演示了用 prefix 在数值前插入图标、用 suffix 在数值后插入单位文本的写法:
import { LikeOutlined } from '@ant-design/icons';
import { Col, Row, Statistic } from 'antd';
const App: React.FC = () => (
<Row gutter={16}>
<Col span={12}>
<Statistic title="Feedback" value={1128} prefix={<LikeOutlined />} />
</Col>
<Col span={12}>
<Statistic title="Unmerged" value={93} suffix="/ 100" />
</Col>
</Row>
);
export default App;
prefix / suffix 的类型都是 ReactNode,因此既可以是字符串、图标,也可以是任意 React 节点。在源码 Statistic.tsx 中,这两个节点分别被包在 -content-prefix 与 -content-suffix 的 <span> 内,夹在数值两侧。
动画效果:自定义 formatter
animated.tsx 展示了如何借助 formatter 接入第三方数字滚动动画库 react-countup,实现“从 0 滚到目标值”的动效:
import CountUp from 'react-countup';
import type { StatisticProps } from 'antd';
import { Col, Row, Statistic } from 'antd';
const formatter: StatisticProps['formatter'] = (value) => (
<CountUp end={value as number} separator="," />
);
// <Statistic title="Active Users" value={112893} formatter={formatter} />
这是 formatter 最常见的用法——当默认的静态数字格式无法满足需求(动画、自定义拼接、金额大写等)时,用 (value) => ReactNode 完全接管数值节点的渲染。源码 Number.tsx 会优先判断 formatter 是否为函数,若是则直接调用并把返回值作为数值节点。
在卡片中使用
card.tsx 将 Statistic 放进 Card 做成指标卡片,并用 styles.content + 颜色来区分涨跌(绿涨红跌):
import { ArrowDownOutlined, ArrowUpOutlined } from '@ant-design/icons';
import { Card, Col, Row, Statistic } from 'antd';
<Card variant="borderless">
<Statistic
title="Active"
value={11.28}
precision={2}
styles={{ content: { color: '#3f8600' } }}
prefix={<ArrowUpOutlined />}
suffix="%"
/>
</Card>
这也是统计类页面的常见布局:外层用 Card / Row / Col 排版,内层用 Statistic 输出指标。需要说明的是,此处用到的是 v6 引入的语义化 styles(旧版写法 valueStyle 已被废弃,请用 styles.content 替代,源码在 Statistic.tsx 中会在开发环境下输出 valueStyle 的废弃告警)。
计时器:倒计时与正计时
timer.tsx 是文档重点介绍的 Statistic.Timer(5.25.0+)能力。它同时支持 countdown(倒计时,如活动结束、抢购剩余时间)与 countup(正计时,如页面已运行时长、通话时长):
import { Col, Row, Statistic } from 'antd';
import type { StatisticTimerProps } from 'antd';
const { Timer } = Statistic;
const deadline = Date.now() + 1000 * 60 * 60 * 24 * 2 + 1000 * 30; // Dayjs is also OK
const before = Date.now() - 1000 * 60 * 60 * 24 * 2 + 1000 * 30;
const onFinish: StatisticTimerProps['onFinish'] = () => {
console.log('finished!');
};
const onChange: StatisticTimerProps['onChange'] = (val) => {
if (typeof val === 'number' && !Number.isNaN(val) && 4.95 * 1000 < val && val < 5 * 1000) {
console.log('changed!');
}
};
<Timer type="countdown" value={deadline} onFinish={onFinish} />
<Timer type="countdown" title="Milliseconds" value={deadline} format="HH:mm:ss:SSS" />
<Timer type="countdown" title="Countdown" value={tenSecondsLater} onChange={onChange} />
<Timer type="countup" title="Countup" value={before} onChange={onChange} />
<Timer type="countdown" title="Day Level" value={deadline} format="D 天 H 时 m 分 s 秒" />
关键约定:
value传毫秒时间戳:countdown模式下为目标时间(未来某刻),countup模式下为起始时间(过去某刻);- 组件以约 60FPS(
1000 / 60ms,见 Timer.tsx)的间隔刷新展示; onChange回传当前剩余/已过毫秒数;onFinish仅countdown模式在归零后触发;format默认HH:mm:ss,支持D、H、m、s、S(毫秒)等时间单位,也支持中文字面量(见源码formatTimeStr的实现)。
自定义语义结构的样式和类
style-class.tsx 演示了 v6 语义化能力:classNames 与 styles 既支持普通对象,也支持函数形式——函数会接收到 { props },从而可以根据当前 props(比如 value 正负)动态决定每个语义节点的样式:
const styleFn: StatisticProps['styles'] = ({ props }): GetProp<StatisticProps, 'styles', 'Return'> => {
const numValue = Number(props.value ?? 0);
const isNegative = Number.isFinite(numValue) && numValue < 0;
if (isNegative) {
return {
title: { color: '#ff4d4f' },
content: { color: '#ff7875' },
value: { backgroundColor: '#fff1f0', borderRadius: 4, paddingInline: 6, userSelect: 'none' },
};
}
return {};
};
<Statistic title="Yearly Loss" value={-18.7} precision={1} styles={styleFn} suffix="%" />
组件 Token(Design Token)定制
component-token.tsx 演示通过 ConfigProvider 的 theme.components.Statistic 统一修改组件的全局设计变量,无需逐例修改:
<ConfigProvider
theme={{
components: {
Statistic: {
titleFontSize: 20,
contentFontSize: 20,
},
},
}}
>
{/* ...Statistic... */}
</ConfigProvider>
Statistic API
通用属性(className、style、id 等)参考 通用属性文档。Statistic 完整参数如下:
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|---|---|---|---|---|
| classNames | 自定义组件内部各语义化结构的 class,支持对象或函数 | Record<SemanticDOM, string> | (info: { props }) => Record<SemanticDOM, string> |
- | 6.0.0 |
| decimalSeparator | 设置小数点 | string | . |
- |
| formatter | 自定义数值展示 | (value) => ReactNode |
- | - |
| groupSeparator | 设置千分位标识符 | string | , |
- |
| loading | 数值是否加载中 | boolean | false | 4.8.0 |
| precision | 数值精度(保留的小数位数) | number | - | - |
| prefix | 设置数值的前缀 | ReactNode | - | - |
| styles | 自定义组件内部各语义化结构的行内 style,支持对象或函数 | Record<SemanticDOM, CSSProperties> | (info: { props }) => Record<SemanticDOM, CSSProperties> |
- | 6.0.0 |
| suffix | 设置数值的后缀 | ReactNode | - | - |
| title | 数值的标题 | ReactNode | - | - |
| value | 数值内容 | string | number | - | - |
styles.content 替代 |
CSSProperties | - | - |
补充说明:
loading依赖 Skeleton 实现;当loading与自定义formatter同时存在时,仍会先渲染 Skeleton 占位再替换为数值。valueStyle在源码 Statistic.tsx 中被显式标记废弃并建议迁移到styles.content。
数值格式化的底层原理
如果不传 formatter,Statistic 会走内置的数字格式化逻辑(见 Number.tsx),主要做了三件事:
- 非法数字原样输出:
value先被转成字符串,用正则/^(-?)(\d*)(\.(\d+))?$/拆出符号、整数部分和小数部分,若匹配失败(如传了非数字字符串)则原样展示; - 千分位分隔:对整数部分执行
int.replace(/\B(?=(\d{3})+(?!\d))/g, groupSeparator),即从右向左每三位插入groupSeparator(默认,,可换成空格、_等); - 小数精度处理:当传入
precision时,小数部分padEnd(precision, '0')补零后截断到指定长度;decimalSeparator(默认.)负责拼接小数点。最终整数与小数分别渲染为-content-value-int与-content-value-decimal两个<span>,为“整数、小数单独着色”之类的视觉需求预留了语义锚点。
同时,Formatter 类型还允许 'number' / 'countdown' 等内置取值,false 可关闭默认格式化,完整类型定义见 utils.ts。
Statistic.Timer(倒计时 / 正计时)
自 5.25.0 起,官方推荐使用 Statistic.Timer 同时覆盖倒计时与正计时两种场景,替代旧的 Statistic.Countdown。文档中 <Badge>5.25.0+</Badge> 标识其引入版本。
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|---|---|---|---|---|
| type | 计时类型,倒计时或正计时 | countdown | countup |
- | - |
| format | 格式化展示,参考 dayjs 的格式串习惯 | string | HH:mm:ss |
- |
| prefix | 设置数值的前缀 | ReactNode | - | - |
| suffix | 设置数值的后缀 | ReactNode | - | - |
| title | 数值的标题 | ReactNode | - | - |
| value | countdown 模式为目标时间、countup 模式为起始时间(毫秒时间戳) |
number | - | - |
| valueStyle | 设置数值区域的样式 | CSSProperties | - | - |
| onFinish | 倒计时完成时触发;countup 模式下不生效 |
() => void |
- | - |
| onChange | 计时变化时触发 | (value: number) => void |
- | - |
Timer 源码级运行机制
从 Timer.tsx 可以看到它的实现思路:
- 刷新节奏:
UPDATE_INTERVAL = 1000 / 60,即以约 60FPS 调用window.setInterval驱动重渲染,保证秒针与毫秒展示都足够平滑; - 方向判定:
const down = type === 'countdown';每次 tick 计算timeDiff = !down ? now - timestamp : timestamp - now,并通过onChange回传; - 终止条件:仅
countdown且当timestamp < now时触发onFinish()并清除定时器,countup永不触发onFinish; - 格式化:内部把计算出的差值交给工具函数
formatCounter(value, config, down),再由formatTimeStr(duration, format)按format拆解为字符串(见 utils.ts)。格式串支持的占位符如下:
| 占位符 | 含义 | 单位置换值 |
|---|---|---|
Y |
年 | 365 天 |
M |
月(按 30 天折算) | 30 天 |
D |
天 | 24 小时 |
H |
小时 | 60 分钟 |
m |
分钟 | 60 秒 |
s |
秒 | 1000 毫秒 |
S |
毫秒 | 1 毫秒 |
占位符支持重复字母以补零(如 HH、ss),多个连续同类字母按最长宽度补足前导 0;如需输出字面文本,可用方括号包裹(如 [天]),算法会先提取方括号内容再在结果中还原,见 utils.ts。这也是示例中 format="D 天 H 时 m 分 s 秒" 能正常展示中文的原因(字母占位符 + 普通中文字面量混排)。
此外,Timer 还通过 valueRender 在内部给数值节点去掉默认 title 提示,避免鼠标悬停时出现多余的 tooltip,细节见 Timer.tsx。
Statistic.Countdown(已废弃)
版本 >= 5.25.0 时,请使用
Statistic.Timer(即<Statistic.Timer type="countdown" />)作为替代方案。
Countdown 参数与 Timer 的 countdown 模式一致,完整 API 如下:
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| format | 格式化倒计时展示,参考 dayjs | string | HH:mm:ss |
| prefix | 设置数值的前缀 | ReactNode | - |
| suffix | 设置数值的后缀 | ReactNode | - |
| title | 数值的标题 | ReactNode | - |
| value | 数值内容(目标时间戳) | number | - |
| valueStyle | 设置数值区域的样式 | CSSProperties | - |
| onFinish | 倒计时完成时触发 | () => void |
- |
| onChange | 倒计时时间变化时触发 | (value: number) => void |
- |
从源码 Countdown.tsx 看,Countdown 本质上只是 StatisticTimer 的薄封装:它固定传 type="countdown",并在开发环境下输出 devUseWarning 的废弃提示,提示开发者迁移到 <Statistic.Timer type="countdown" />。因此阅读或维护旧代码时可以直接把 <Statistic.Countdown> 替换为 <Statistic.Timer type="countdown">,其余 format、onFinish、onChange 等属性保持不变。而在聚合入口 index.tsx 中,Statistic.Timer 与 Statistic.Countdown 都是作为静态属性挂在 Statistic 上的组合组件。
Semantic DOM(语义化节点)
v6 起 Statistic 暴露了完整的语义化 DOM 结构,方便在不触碰内部实现的前提下做精准的样式与类名定制。Statistic 提供以下语义节点:root、header、title、content、value、prefix、suffix。
结合源码 Statistic.tsx 的渲染结构与 demo/_semantic.tsx 中的语义说明,各节点的实际 CSS 类名与职责如下:
| 语义节点 | 对应类名(prefixCls 默认 ant-statistic) |
结构职责 | 版本 |
|---|---|---|---|
| root | ant-statistic |
根容器,承载整体布局与重置样式 | 6.0.0 |
| header | ant-statistic-header |
头部区域,包含标题的布局与下内边距 | 6.0.0 |
| title | ant-statistic-title |
标题文字(颜色、字号等) | 6.0.0 |
| content | ant-statistic-content |
内容区,负责 prefix / value / suffix 的水平对齐 | 6.0.0 |
| value | ant-statistic-content-value |
数值本体(字号、字重、字族、颜色) | 6.4.0 |
| prefix | ant-statistic-content-prefix |
数值前缀(inline-block、右外边距) | 6.0.0 |
| suffix | ant-statistic-content-suffix |
数值后缀(inline-block、左外边距) | 6.0.0 |
value 节点内部还细分出 -content-value-int(整数部分)与 -content-value-decimal(小数部分)两个 span(见 Number.tsx),不过文档层面暴露的语义化入口以 value 为最小单位。各语义节点可通过 classNames(追加 class)与 styles(追加行内样式)以“对象”或“接收 { props } 的函数”两种形态进行定制,例如:
<Statistic
title="Active Users"
value={93241}
styles={{
title: { color: '#1890ff', fontWeight: 600 },
content: { fontSize: '24px' },
value: { color: '#0958d9', backgroundColor: '#e6f4ff', borderRadius: 4, paddingInline: 6 },
}}
suffix="users"
/>
主题变量(Design Token)
Statistic 支持通过 ConfigProvider 的组件级主题变量进行全局定制。可用 Token 定义于 style/index.ts,核心两个变量为:
| Token | 说明 | 默认值 |
|---|---|---|
titleFontSize |
标题(title)的字号 | fontSize(默认 14px) |
contentFontSize |
内容(数值区域)的字号 | fontSizeHeading3(默认 24px) |
对应的默认值来自 prepareComponentToken:titleFontSize: fontSize、contentFontSize: fontSizeHeading3,即标题默认沿用全局正文字号、数值默认使用三级标题字号(更大一号),从设计上保证“标题小、数值大”的阅读层级。使用时只需在应用根部包裹 ConfigProvider:
<ConfigProvider
theme={{
components: {
Statistic: { titleFontSize: 14, contentFontSize: 28 },
},
}}
>
<App />
</ConfigProvider>
如需精确到组件或数值局部覆盖,则优先使用上文介绍的语义化 styles / classNames,二者共同构成“Token 全局定制 + 语义节点局部定制”的两层样式体系。
进阶提示与最佳实践小结
- 组件是无状态展示层:Statistic 不负责拉取数据,请自行在上层管理数据源;异步场景可结合
loading提供骨架占位。 - 数字格式化优先走内置参数:千分位用
groupSeparator、小数位用precision、单位用prefix/suffix;只有动画、富文本等高级需求才需要自定义formatter(参考 animated.tsx 中与react-countup的组合方式)。 - 倒计时请使用
Statistic.Timer:它同时支持countdown与countup双向计时,旧的Statistic.Countdown在 5.25.0 后已被废弃。 - 样式定制优先语义化节点:v6 中请使用
classNames/styles(含函数式动态样式),valueStyle已废弃并会触发开发环境告警。 - 需要取到底层 DOM 时,可通过 ref 获取
nativeElement(类型StatisticRef,见 Statistic.tsx),例如用于测量宽度或做滚动监听。
Statistic 组件结构清晰、扩展点集中,其语义化 DOM 设计在同类数据展示场景(如数值大盘、监控指标)中有很强的复用参考价值。若需要查看更多运行示例,可直接浏览 components/statistic/demo 目录下的各示例文件;相关自动化测试与快照覆盖见 components/statistic/tests,其中 semantic.test.tsx 可用于了解语义节点结构的断言方式。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00