- UI组件
- 前端
【免费下载链接】ng-zorro-antd
Angular UI Component Library based on Ant Design
导读
本文是围绕 ng-zorro-antd(Angular UI 组件库,基于 Ant Design)中nz-countdown倒计时组件编写的实战指南。倒计时组件常用于电商大促抢购、活动开始时间、考试倒计时、运营倒计时等需要突出展示"距离某个时间点还剩多久"的场景。读完本文,你将掌握nz-countdown的全部 API 用法、nzFormat占位符格式化规则、(nzCountdownFinish)完成事件,并深入理解其基于NgZone与定时器的源码实现原理与测试验证方式。
一、组件定位:Statistic 家族中的"动态数字"
nz-countdown属于 ng-zorro-antd 的 Statistic(统计)组件体系,用于"展示统计数字"。当需要突出某个或某组数字、并展示带描述的统计类数据时,可以使用nz-statistic;而当这个数字是"动态递减的剩余时间"时,就应该使用nz-countdown。
从组件结构上看,NzCountdownComponent直接继承自NzStatisticComponent(见 countdown.component.ts),它复用父组件的前缀、后缀、标题、值样式与自定义模板能力,只是把静态数值替换为"目标时间与当前时间的差值(diff)",并通过内部定时器不断刷新。因此,nz-statistic的绝大部分外观与布局能力,倒计时组件都天然具备。
两个组件统一由NzStatisticModule提供(见 statistic.module.ts),引入方式:
import { NzStatisticModule } from 'ng-zorro-antd/statistic';二、快速上手:官方 Demo 示例
官方示例位于 countdown.ts,对应的文档页面是 countdown.md。它在一个nz-row网格中展示了三种典型用法:默认格式、毫秒级格式、中文自定义格式。
import { Component } from '@angular/core'; import { NzGridModule } from 'ng-zorro-antd/grid'; import { NzStatisticModule } from 'ng-zorro-antd/statistic'; @Component({ selector: 'nz-demo-statistic-countdown', imports: [NzGridModule, NzStatisticModule], template: ` <nz-row [nzGutter]="16"> <nz-col [nzSpan]="12"> <nz-countdown [nzValue]="deadline" nzTitle="Countdown" /> </nz-col> <nz-col [nzSpan]="12"> <nz-countdown [nzValue]="deadline" nzTitle="Million Seconds" nzFormat="HH:mm:ss:SSS" /> </nz-col> <nz-col [nzSpan]="24" style="margin-top: 32px;"> <nz-countdown [nzValue]="deadline" nzTitle="Day Level" nzFormat="D 天 H 时 m 分 s 秒" /> </nz-col> </nz-row> ` }) export class NzDemoStatisticCountdownComponent { deadline = Date.now() + 1000 * 60 * 60 * 24 * 2 + 1000 * 30; }示例要点解读:
deadline是毫秒时间戳(Date.now() + 2 天 + 30 秒),即"从现在起 2 天 30 秒后"这个目标时刻;- 第一个倒计时使用默认格式
HH:mm:ss,展示48:00:30这类时分秒; - 第二个倒计时追加
SSS占位符,展示毫秒位,适合需要高精度感知的场景(如活动秒杀倒计时); - 第三个倒计时使用中文格式串
D 天 H 时 m 分 s 秒,格式化后的文本会原样保留汉字与空格,呈现为2 天 0 时 0 分 30 秒,说明nzFormat是"占位符 + 任意字面文本"的自由组合。
三、API 详解:nz-countdown 全部参数
以下参数表来自官方文档 index.zh-CN.md(英文版见 index.en-US.md),并结合源码核对:
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
[nzFormat] | 格式化倒计时展示 | string | 'HH:mm:ss' |
[nzPrefix] | 设置数值的前缀 | string \| TemplateRef<void> | - |
[nzSuffix] | 设置数值的后缀 | string \| TemplateRef<void> | - |
[nzTitle] | 数值的标题 | string \| TemplateRef<void> | - |
[nzValue] | 时间戳格式的目标时间 | string \| number | - |
[nzValueTemplate] | 自定义时间展示 | TemplateRef<{ $implicit: number }> | - |
(nzCountdownFinish) | 当倒计时完成时发出事件 | void | - |
逐个说明:
[nzValue](必填):目标时间,接受字符串或数字形式的毫秒时间戳。组件在ngOnChanges中通过Number(nzValue.currentValue)将其转换为内部target(见 countdown.component.ts),因此传入数字字符串同样有效。[nzFormat]:倒计时展示格式,默认HH:mm:ss。支持Y/M/D/H/m/s/S七种占位符(详见下文)。[nzPrefix]/[nzSuffix]/[nzTitle]:与nz-statistic一致,既支持普通字符串,也支持TemplateRef。源码中通过nzStringTemplateOutlet结构指令统一渲染两种形态(见 statistic.component.ts),例如nzPrefix="距开奖还有"或传入一个模板。[nzValueTemplate]:自定义倒计时内容展示。类型为TemplateRef<{ $implicit: number }>,即模板上下文会暴露$implicit变量,其值为当前剩余毫秒数diff。若未提供,则使用内置模板{{ diff | nzTimeRange: nzFormat }}(见 countdown.component.ts)。参考测试用例 countdown.component.spec.ts:
<ng-template #tpl let-diff> {{ diff }} </ng-template>(nzCountdownFinish):当倒计时归零时触发的事件。源码中在updateValue()内检测diff === 0后停止定时器并发出事件(见 countdown.component.ts)。
nzFormat 占位符
| 占位符 | 描述 |
|---|---|
Y | 年 |
M | 月 |
D | 日 |
H | 时 |
m | 分 |
s | 秒 |
S | 毫秒 |
占位符支持重复书写以控制位数:例如HH:mm:ss每位固定两位(不足补零),HH:mm:ss:SSS毫秒占三位。官方文档(index.zh-CN.md 的 nzFormat 小节)给出的S描述为"毫秒",与源码时间单位表一致(见 time.ts 中['S', 1],即 1 毫秒)。需要特别留意:这里的M代表"月",按 30 天折算(1000 * 60 * 60 * 24 * 30),Y按 365 天折算,因此仅适合做"粗略时长"展示,不宜用于精确的年月历法计算。
四、格式化原理:nzTimeRange 管道与时间单位表
倒计时的格式化并非组件内硬编码,而是由核心管道nzTimeRange完成(time-range.pipe.ts)。其核心逻辑如下:
@Pipe({ name: 'nzTimeRange' }) export class NzTimeRangePipe implements PipeTransform { transform(value: string | number, format: string = 'HH:mm:ss'): string { let duration = Number(value || 0); return timeUnits.reduce((current, [name, unit]) => { if (current.indexOf(name) !== -1) { const v = Math.floor(duration / unit); duration -= v * unit; return current.replace(new RegExp(`${name}+`, 'g'), (match: string) => padStart(v.toString(), match.length, '0') ); } return current; }, format); } }工作流程可以拆解为四步:
- 把剩余毫秒数
duration作为被除数; - 按照 time.ts 中定义的单位表(
Y=365 天毫秒数、M=30 天毫秒数、D=1 天毫秒数、H=1 小时毫秒数、m=1 分钟毫秒数、s=1 秒毫秒数、S=1 毫秒)依次处理; - 对格式串中出现的每个占位符,计算
Math.floor(duration / unit)得到该时间单位上的数值,并从总时长中扣除(duration -= v * unit),保证各占位符数值互不重叠、正确进位; - 使用
padStart(来自 core/util)把数值按占位符重复长度补零,例如m输出5,mm输出05。
这种"逐单位扣除"的算法决定了格式串中占位符的排列顺序语义:虽然nzFormat允许自由排列占位符,但各单位的数值是按照时间单位的固定顺序(Y→M→D→H→m→s→S)依次计算和扣减的,建议按从大到小书写,符合直觉且不易出错。
五、源码实现:定时器、NgZone 与完成事件
理解nz-countdown的运行机制,关键在于 countdown.component.ts 中的生命周期与定时器管理:
1. 刷新频率
const REFRESH_INTERVAL = 1000 / 30; // 约 33ms,即每秒约 30 帧定时器以约 33ms 的间隔刷新diff,足以让毫秒位(SSS)肉眼可见地连续跳动,同时避免过高频率带来的无谓开销。
2. 生命周期与定时器启停
ngOnChanges:当nzValue变化时更新target;若非首次变化,立即调用syncTimer()重新同步定时器(支持运行时动态修改目标时间);ngOnInit:初始化时调用syncTimer();syncTimer():比较target >= Date.now()决定启动还是停止定时器——目标时间已经过去则直接停止;startTimer():仅在platform.isBrowser(浏览器环境)下启动;通过ngZone.runOutsideAngular把setInterval放在 Angular Zone 之外,避免每秒 30 次触发变更检测影响整个应用性能,然后在回调内手动调用this.cdr.detectChanges()精确更新本组件视图;stopTimer():clearInterval并置空引用;destroyRef.onDestroy:组件销毁时自动停止定时器,避免内存泄漏(见 countdown.component.ts)。
3. diff 计算与完成事件
protected updateValue(): void { this.diff = Math.max(this.target - Date.now(), 0); if (this.diff === 0) { this.stopTimer(); if (this.nzCountdownFinish.observers.length) { this.ngZone.run(() => this.nzCountdownFinish.emit()); } } }三个细节值得注意:
Math.max(..., 0)保证归零后不显示负数;- 归零时立即停止定时器,不再空转;
- 完成事件通过
ngZone.run()重新进入 Angular Zone 发出,确保订阅者在事件回调中对状态/信号的更新能正常触发变更检测。
六、测试验证:行为如何被保障
组件行为由 countdown.component.spec.ts 覆盖,测试采用vi.useFakeTimers()+vi.setSystemTime()固定系统时间,再通过vi.advanceTimersByTime()快进时钟来验证,其中包含四条关键用例:
- 正确渲染时间:目标时间设为"2 天 + 30 秒"后,快进 100ms,断言渲染结果为
48:00:29(24 小时制的 H 位会累加,2 天 = 48 小时),验证HH:mm:ss格式化与逐位补零正确; - 目标时间早于当前时停止:将
nzValue设为过去的时间点,断言展示00:00:00且stopTimer被调用一次,验证syncTimer的"过期即停"逻辑; - 模板支持:通过
nzValueTemplate自定义展示,验证上下文$implicit传入的是剩余毫秒数; - 完成事件:目标设为"当前 + 2 秒",快进 3 秒后断言
(nzCountdownFinish)被触发(finished计数为 1),验证归零发事件与定时器停止。
这些用例直接印证了上一节描述的定时器启停、归零保护和事件发射行为,可作为二次开发或定制倒计时组件时的行为基线参考。
七、配套能力:从倒计时到完整统计展示
nz-countdown在继承NzStatisticComponent的同时,也继承了nz-statistic的完整展示能力(见 statistic.component.ts 的模板结构):
[nzLoading]:加载状态,置为true时内容区域渲染nz-skeleton骨架屏占位;[nzValueStyle]:作用于.ant-statistic-content的样式对象(类型为NgStyleInterface),可用于控制数字的字体大小、颜色等;- RTL 支持:宿主元素根据
Directionality自动追加ant-statistic-rtl类,适配从右到左的布局; - 样式文件位于 style/index.less,类名体系为
ant-statistic、ant-statistic-title、ant-statistic-content、ant-statistic-content-prefix/suffix、ant-statistic-content-value等,可通过覆盖这些类自定义外观。
八、常见用法小结
| 需求 | 写法 |
|---|---|
| 最简倒计时 | <nz-countdown [nzValue]="deadline" nzTitle="Countdown" /> |
| 显示毫秒 | nzFormat="HH:mm:ss:SSS" |
| 中文单位 | nzFormat="D 天 H 时 m 分 s 秒" |
| 自定义内容模板 | <ng-template #tpl let-diff>{{ diff | number }} 毫秒</ng-template> |
| 完成后回调 | (nzCountdownFinish)="onFinish()" |
| 动态更新目标时间 | 修改绑定的nzValue,组件自动syncTimer() |
相关参考文件:官方 API 文档 index.zh-CN.md 与 index.en-US.md、基础示例 basic.ts 与 unit.ts(自定义单位)、组件源码 countdown.component.ts 与 statistic.component.ts、格式化管道 time-range.pipe.ts、时间单位表 time.ts。
- UI组件
- 前端
【免费下载链接】ng-zorro-antd
Angular UI Component Library based on Ant Design
相关推荐
ng-zorro-antd Statistic 统计组件与 Countdown 倒计时完整指南:API 详解与源码原理
ng zorro antd Statistic 统计组件与 Countdown 倒计时完整指南:API 详解与源码原理 ng zorro antd 是基于 An
UI组件前端ng-zorro-antd Statistic 组件完全指南:统计数字展示与倒计时实战
ng zorro antd Statistic 组件完全指南:统计数字展示与倒计时实战 导读 本文围绕 Angular UI 组件库 ng zorro antd
UI组件前端Ant Design Statistic 统计数值组件完全指南:格式化、倒计时与源码级实现原理
Ant Design Statistic 统计数值组件完全指南:格式化、倒计时与源码级实现原理 导读 Statistic(统计数值)是 Ant Design 中
前端UI组件设计系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考