Element Plus Statistic 统计数值与 Countdown 倒计时组件完全指南:从基础用法到源码级原理
【免费下载链接】element-plus🎉 A Vue.js 3 UI Library made by Element team项目地址: https://gitcode.com/GitHub_Trending/el/element-plus
Statistic 是 Element Plus 中用于突出展示单个或一组数字(如统计值、金额、排名)的展示型组件,Countdown 则基于 Statistic 实现了面向目标时间点的倒计时能力。本文以 官方文档 为骨架,结合 statistic.vue、countdown.vue 等源码实现与测试用例,系统讲解两者的全部 API、格式化与数字分组原理、组合插槽玩法、动画过渡技巧,以及主题定制方式,让你既能开箱即用,也能深入理解其底层工作机制。
一、组件概览:Statistic 与 Countdown 的关系
Statistic(统计数值)是一个纯展示型组件,负责以统一、美观的排版呈现数字;Countdown(倒计时)则是在 Statistic 之上封装的计时组件——它通过 countdown.vue 内部直接渲染el-statistic并把「剩余时间」作为 value 传入,因此 Countdown 天然继承了 Statistic 的 title、prefix、suffix、value-style 等全部展示能力,同时额外提供 format、change、finish 等计时专属 API。
两者在组件树中的注册方式一致:ElStatistic通过 index.ts 中的withInstall完成全局安装,组件 name 为ElStatistic/ElCountdown。你可以全局注册后直接使用,也可以按需引入:
import { ElStatistic, ElCountdown } from 'element-plus'二、Statistic 基础用法与数字格式化
2.1 最小示例
<template> <el-statistic title="Daily active users" :value="268500" /> </template>渲染结果中,标题「Daily active users」显示在数值上方,数值按千位分隔符格式化为268,500。
2.2 格式化管线:千分位、小数精度与分隔符
Statistic 的数值格式化并非由第三方库完成,而是由 statistic.vue 中的displayValue计算属性实现,核心逻辑如下:
let [integer, decimal = ''] = String(value).split('.') decimal = decimal.padEnd(precision, '0').slice(0, precision > 0 ? precision : 0) integer = integer.replace(/\B(?=(\d{3})+(?!\d))/g, groupSeparator) return [integer, decimal].join(decimal ? decimalSeparator : '')这条管线的处理顺序可以拆解为四步:
- 整数/小数分离:先把数值转成字符串,按小数点拆分为
integer与decimal两部分; - 小数补位与截断:用
padEnd(precision, '0')补足precision指定的精度,再slice截断超出部分。因此precision: 0(默认值)时小数部分会被完全去掉;precision: 2时268500.1会显示为268500.10; - 千分位分组:通过正则
\B(?=(\d{3})+(?!\d))从右往左每三位插入groupSeparator(默认,),于是268500变为268,500; - 拼接回显:仅在存在小数位时,才用
decimalSeparator(默认.)连接整数与小数部分。
该行为有对应测试用例佐证,见 statistic.test.tsx:value={57454157}渲染为57,454,157;value={268500.123456}在默认精度下渲染为268,500,将precision从 6 动态改为 4 后立即变为268,500.1234。
2.3 自定义分隔符与小数精度
不同业务场景下,你通常需要自定义千位分隔符与小数点符号:
<template> <el-statistic title="销售金额" :value="1234567.891" :precision="2" group-separator="," decimal-separator="." prefix="¥" /> </template>对应属性在 statistic.ts 中的默认值分别为:decimalSeparator: '.'、groupSeparator: ','、precision: 0。例如欧元区可设置group-separator="."、decimal-separator=","以适配本地数字习惯。
2.4 formatter:完全自定义展示
当内置的千分位/精度规则无法满足需求(如单位换算、条件着色)时,使用formatter接管数值渲染:
<template> <el-statistic title="转化率" :value="0.8723" :formatter="formatRate" /> </template> <script lang="ts" setup> function formatRate(value: number) { return `${(value * 100).toFixed(1)}%` } </script>从源码看,displayValue的优先级是:只要传入了formatter函数,就直接返回formatter(value)的结果,跳过内置格式化管线。因此formatter与precision、group-separator等属性互斥,二者不要同时使用。
2.5 一个易被忽略的边界情况
源码中对非数值类型做了防御处理(对应 issue 修复,见 statistic.vue 中注释):
if (!isNumber(value) || Number.isNaN(value)) return value即当value不是数字或为NaN时,原样输出该值,避免对undefined、字符串等调用.split产生异常。类型层面value支持number | Dayjs(通过definePropType定义),但传入Dayjs对象时 Statistic 会原样渲染,实际面向时间对象的格式化能力由 Countdown 的format承担。
三、组合式用法:图标、单位与自定义插槽
Statistic 的模板结构(见 statistic.vue)非常清晰,渲染层级为:
.el-statistic ├── .el-statistic__head (title 区,有 title 或插槽才渲染) └── .el-statistic__content ├── .el-statistic__prefix (prefix 区) ├── .el-statistic__number (数值,应用 value-style) └── .el-statistic__suffix (suffix 区)你可以在数字前后附加图标与单位,官方基础示例 basic.vue 展示了四种典型组合:
- 标题使用
#title插槽,嵌入el-icon与文案(如「Ratio of men to women」旁的性别图标); - 数字前通过
#prefix插槽放图标或单位; - 数字后通过
#suffix插槽追加单位或图标(如#suffix中的/100、反馈数旁的ChatLineRound图标)。
需要特别说明:prefix、suffix、title三个属性与同名插槽是叠加渲染的关系——传了属性会渲染默认插槽内容(<span>{{ prefix }}</span>),再传入同名插槽则完全替换默认内容。例如:
<el-statistic title="Feedback number" :value="562"> <template #suffix> <el-icon style="vertical-align: -0.125em"> <ChatLineRound /> </el-icon> </template> </el-statistic>四、为数值添加动画过渡(vueuse useTransition)
Statistic 本身不内置动画,官方推荐结合@vueuse/core的useTransition为数值添加平滑的数字滚动/递增效果。核心思想是:先用 ref 保存目标值,再通过useTransition生成一个随时间缓动逼近目标值的响应式数值,绑定给:value:
<script lang="ts" setup> import { ref } from 'vue' import { useTransition } from '@vueuse/core' import { ChatLineRound, Male } from '@element-plus/icons-vue' const source = ref(0) const outputValue = useTransition(source, { duration: 1500, }) source.value = 172000 </script> <template> <el-statistic title="Total Transactions" :value="outputValue" /> </template>当source.value改变时,useTransition会在 1500ms 内输出从旧值平滑过渡到新值的中间值,Statistic 的displayValue随之持续重算,视觉上即为数字滚动增长效果。完整示例见 basic.vue。useTransition支持transition(缓动函数)、duration、ease等选项,可用于金币余额、成交量、榜单分数的入场动画。
五、Countdown 倒计时:格式化与事件体系
5.1 基本用法
<template> <el-countdown title="Start to grab" :value="value" /> </template> <script lang="ts" setup> import { ref } from 'vue' const value = ref(Date.now() + 1000 * 60 * 60 * 7) </script>value接受目标时间(未来时间点),可以是时间戳(number)或Dayjs对象。Countdown 会在挂载后每秒刷新剩余时间,默认以HH:mm:ss格式显示。
5.2 format 格式化模板与「天数」建议
format默认值为HH:mm:ss,格式化能力来自 countdown/src/utils.ts 中的formatTime。其时间单位映射如下:
| 占位符 | 含义 | 换算单位 |
|---|---|---|
Y | 年 | 365 天 |
M | 月 | 30 天 |
D | 天 | 24 小时 |
H | 时 | 60 分钟 |
m | 分 | 60 秒 |
s | 秒 | 1000 毫秒 |
S | 毫秒 | 1 毫秒 |
格式化时按上述顺序依次用整数除法取商并扣除已用掉的时间,再用padStart按占位符长度补零。例如format="DD [days] HH:mm:ss"会输出02 days 05:30:00这种带文字描述的形式——方括号[...]内的文本会被原样输出,这是文档建议将格式化范围控制在「天」级别的原因(官方文档 tip:In formatting it is suggested to be in the range of days)。典型的日级倒计时写法:
<el-countdown format="DD [days] HH:mm:ss" :value="value2" />5.3 事件:change 与 finish
Countdown 通过 countdown.ts 中的countdownEmits声明了两个事件:
| 事件 | 触发时机 | 回调参数 |
|---|---|---|
change | 每一帧(rAF 回调)触发 | 剩余时间差(毫秒,number) |
finish | 倒计时归零 | 无参数 |
在 countdown.vue 的startTimer中可以看到完整计时循环:取目标时间戳减去Date.now()得到差值diff;若diff > 0则持续通过requestAnimationFrame(rAF)调度下一帧并 emitchange;一旦diff <= 0,则钳制为 0、取消定时器并 emitfinish。这意味着change 的触发频率约等于屏幕刷新率,可用于驱动进度条、震动手感等高频反馈;而 finish 适合触发「活动结束」「开抢」等一次性动作。
<el-countdown :value="endTime" format="HH:mm:ss" @change="(v: number) => console.log('剩余毫秒', v)" @finish="onFinish" />5.4 value 变化的响应式重启
源码通过watch(() => [props.value, props.format], ...)监听目标时间与格式:只要二者任一变化,就stopTimer()停掉旧循环并startTimer()以新目标重启,immediate: true保证挂载即开始。因此动态「重置倒计时」非常自然——官方示例 countdown.vue 中的 Reset 按钮正是通过重新赋值value1实现的。
5.5 生命周期与内存安全
onBeforeUnmount中调用stopTimer()取消 rAF 定时器,避免组件卸载后定时器继续触发更新泄漏。这是使用 rAF 计时组件时值得参考的收尾模式。
六、插槽体系与 Card 风格组合
6.1 Countdown 插槽
Countdown 的模板通过v-for透传所有具名插槽给内部el-statistic,因此prefix、suffix、title三个插槽完全对齐 Statistic:
<el-countdown format="DD [days] HH:mm:ss" :value="value2"> <template #title> <div style="display: inline-flex; align-items: center"> <el-icon style="margin-right: 4px" :size="12"> <Calendar /> </el-icon> Still to go until next month </div> </template> </el-countdown>6.2 卡片式统计面板
官方「Card usage」示例 card.vue 演示了 Statistic 与el-row/el-col网格、el-tooltip提示、图标和底部涨跌标记的自由组合,构成大屏/后台常见的指标卡片:
- 标题区使用
#title插槽,内部嵌入el-icon与el-tooltip(content属性承载指标口径说明,placement="top"控制气泡位置); - 底部用自定义 div 呈现「than yesterday +24%」等同比环比信息,涨跌颜色通过
--el-color-success/--el-color-error主题变量控制; - 卡片样式由 scoped CSS 实现:
padding: 20px、border-radius: 4px、背景色--el-bg-color-overlay,并用:global(h2#card-usage ...)选择器为示例展示区覆盖底色。
此类组合适合数据看板、运营后台、财务汇总页,Statistic 只负责「数字展示」这一件事,其余布局完全由你自由编排。
七、暴露的实例方法:displayValue
Statistic 与 Countdown 均通过defineExpose暴露只读的displayValue:
| 组件 | 暴露类型 | 含义 |
|---|---|---|
| Statistic | Ref<string \| number> | 当前展示值(可能是格式化后的字符串,也可能是 formatter 返回值) |
| Countdown | Ref<string> | 当前格式化后的剩余时间字符串 |
可在父组件通过模板 ref 读取:
<el-statistic ref="statisticRef" :value="268500" />import { ref } from 'vue' const statisticRef = ref() // statisticRef.value.displayValue // '268,500'八、样式定制:CSS 变量与主题色
Statistic 的视觉风格完全由 CSS 变量驱动,定义在 theme-chalk/src/common/var.scss 中,并通过 statistic.scss 注入组件作用域:
| CSS 变量 | 默认值 | 作用 |
|---|---|---|
--el-statistic-title-font-weight | 400 | 标题字重 |
--el-statistic-title-font-size | var(--el-font-size-extra-small) | 标题字号 |
--el-statistic-title-color | var(--el-text-color-regular) | 标题颜色 |
--el-statistic-content-font-weight | 400 | 数值字重 |
--el-statistic-content-font-size | var(--el-font-size-extra-large) | 数值字号 |
--el-statistic-content-color | var(--el-text-color-primary) | 数值颜色 |
在任意作用域覆盖即可实现主题化,官方卡片示例正是通过这种方式把数值放大到 28px:
.el-statistic { --el-statistic-content-font-size: 28px; }布局细节上,.el-statistic__prefix与.el-statistic__suffix分别有margin-right: 4px、margin-left: 4px的间距,数值.el-statistic__number为inline-block,标题与内容之间margin-bottom: 4px,整体无需额外样式即可获得干净的对齐排版。
九、按需引入与全局注册
- 全局注册:
app.use(ElementPlus)会一并注册ElStatistic与ElCountdown(二者已包含在 packages/components/index.ts 的导出清单中); - 按需引入(配合
unplugin-vue-components的ElementPlusResolver):
import { ElStatistic, ElCountdown } from 'element-plus' app.use(ElStatistic) app.use(ElCountdown)样式方面,组件对应样式位于 theme-chalk,全量引入主题包或按需样式插件均可生效。
十、小结:API 速查表
| 功能 | 组件 | 核心属性 | 关键事件/插槽 |
|---|---|---|---|
| 统计数值展示 | el-statistic | value、formatter、precision、group-separator、decimal-separator、prefix、suffix、title、value-style | 插槽:prefix/suffix/title;暴露:displayValue |
| 倒计时 | el-countdown | value(number / Dayjs)、format(默认HH:mm:ss)、prefix、suffix、title、value-style | 事件:change/finish;插槽与暴露同上 |
实践要点回顾:
- 数值动画使用
useTransition绑定:value,无需额外依赖组件内部能力; - 长周期倒计时优先用
DD [days] HH:mm:ss这类「天」级模板,格式化逻辑在 countdown/src/utils.ts 中按 Y → M → D → H → m → s → S 顺序递减换算; change事件按帧触发(rAF),finish事件在归零瞬间触发,二者配合可实现抢购、到期、进度反馈等场景;- 主题定制直接覆盖
--el-statistic-*CSS 变量,数值与标题的字号、字重、颜色均可独立控制。
【免费下载链接】element-plus🎉 A Vue.js 3 UI Library made by Element team项目地址: https://gitcode.com/GitHub_Trending/el/element-plus
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考