HarmonyOS 鸿蒙Next中如何实现自定义倒计时功能?可支持自定义时间格式(HH:MM:SS/MM:SS)
HarmonyOS 鸿蒙Next中如何实现自定义倒计时功能?可支持自定义时间格式(HH:MM:SS/MM:SS) 如何实现自定义倒计时功能?要求支持自定义时间格式(HH:MM:SS/MM:SS)、可配置倒计时时长、倒计时结束触发自定义业务逻辑(如启用按钮、提示用户),适配多版本且无需依赖额外资源包?
我们开发 HarmonyOS 应用时,常需实现倒计时功能(如验证码倒计时、活动倒计时、提交按钮冷却倒计时),要求支持自定义时间格式(HH:MM:SS/MM:SS)、可配置倒计时时长、倒计时结束触发自定义业务逻辑(如启用按钮、提示用户)等,这里就给大家一个基本的实现示例
一、核心点
1. 核心倒计时逻辑(Timer 实现)
使用setInterval创建每秒执行的定时器,通过remainingSeconds记录剩余秒数,每秒递减;
封装clearTimer方法统一管理定时器销毁,避免多次创建定时器导致倒计时加速;
2. 自定义时间格式
支持HH:MM:SS(时:分: 秒)和MM:SS(分:秒)两种格式,通过formatType状态切换;
封装formatTime通用格式化方法,内置padZero补零函数,确保时间显示为两位数(如 01:02 而非 1:2);
MM:SS格式自动将小时转换为分钟(如 1 小时 20 分钟 = 80:00),适配短时长倒计时场景。
3. 灵活的倒计时控制
开始:支持传入自定义总秒数,重置并启动倒计时;
暂停:保留当前剩余秒数,停止定时器;
重置:恢复初始倒计时秒数,停止定时器。
4. 结束回调(自定义业务逻辑)
封装onCountdownFinish方法,倒计时结束时触发,示例中实现 “启用按钮” 逻辑;
可按需扩展:如弹出提示、提交表单、跳转页面等,无需修改核心倒计时逻辑。
二、关键代码实现
时间格式化:
/**
* 格式化时间:根据指定格式转换秒数为 HH:MM:SS 或 MM:SS
* @param seconds 剩余秒数
* @returns 格式化后的时间字符串
*/
private formatTime(seconds: number): string {
// 处理负数情况
if (seconds < 0) seconds = 0;
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = seconds % 60;
// 补零函数:确保数字为两位数
const padZero = (num: number): string => num.toString().padStart(2, '0');
if (this.formatType === 'HH:MM:SS') {
return `${padZero(hours)}:${padZero(minutes)}:${padZero(secs)}`;
} else {
// MM:SS格式:小时自动转换为分钟(如120秒=02:00,3720秒=62:00)
const totalMinutes = Math.floor(seconds / 60);
return `${padZero(totalMinutes)}:${padZero(secs)}`;
}
}
倒计时结束回调:
/**
* 倒计时结束回调(自定义业务逻辑)
*/
private onCountdownFinish(): void {
console.log('倒计时结束:触发自定义业务逻辑');
// 示例1:启用按钮
this.btnDisabled = false;
// 示例2:弹窗提示(可根据需求扩展)
// promptAction.showToast({ message: '倒计时结束!' });
}
}
三、完整代码
// components/CountdownTimer/CountdownTimer.ets
@Entry
@Component
struct CountdownTimerDemo {
// 倒计时核心状态
@State remainingSeconds: number = 120; // 总倒计时秒数(示例:2分钟)
@State isCounting: boolean = false; // 是否正在倒计时
@State timerId: number = -1; // 定时器ID,用于销毁定时器
@State formatType: 'HH:MM:SS' | 'MM:SS' = 'MM:SS'; // 时间格式类型
@State btnDisabled: boolean = true; // 示例:倒计时结束启用按钮
build() {
Column() {
// 倒计时显示区域
Text(this.formatTime(this.remainingSeconds))
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor('#3498DB')
.margin(30);
// 格式切换按钮
Row() {
Button('HH:MM:SS格式')
.onClick(() => {
this.formatType = 'HH:MM:SS';
})
.backgroundColor(this.formatType === 'HH:MM:SS' ? '#3498DB' : '#F5F5F5')
.fontColor(this.formatType === 'HH:MM:SS' ? '#FFFFFF' : '#333333')
.margin(5);
Button('MM:SS格式')
.onClick(() => {
this.formatType = 'MM:SS';
})
.backgroundColor(this.formatType === 'MM:SS' ? '#3498DB' : '#F5F5F5')
.fontColor(this.formatType === 'MM:SS' ? '#FFFFFF' : '#333333')
.margin(5);
}
.margin(10);
// 操作按钮组
Row() {
Button('开始倒计时',{ type: ButtonType.Capsule, stateEffect: this.isCounting})
.onClick(() => {
this.startCountdown(120); // 重置为2分钟倒计时并开始
})
.margin(5);
Button('暂停倒计时',{ type: ButtonType.Capsule, stateEffect: !this.isCounting})
.onClick(() => {
this.pauseCountdown();
})
.margin(5);
Button('重置倒计时')
.onClick(() => {
this.resetCountdown();
})
.margin(5);
}
.margin(20);
// 示例:倒计时结束启用的业务按钮
Button('倒计时结束可点击',{ type: ButtonType.Capsule, stateEffect: this.btnDisabled})
.onClick(() => {
console.log('业务按钮触发:倒计时已结束');
})
.backgroundColor(this.btnDisabled ? '#CCCCCC' : '#2ECC71')
.fontColor('#FFFFFF')
.margin(10);
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.backgroundColor('#F8F9FA')
}
/**
* 格式化时间:根据指定格式转换秒数为 HH:MM:SS 或 MM:SS
* @param seconds 剩余秒数
* @returns 格式化后的时间字符串
*/
private formatTime(seconds: number): string {
// 处理负数情况
if (seconds < 0) seconds = 0;
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = seconds % 60;
// 补零函数:确保数字为两位数
const padZero = (num: number): string => num.toString().padStart(2, '0');
if (this.formatType === 'HH:MM:SS') {
return `${padZero(hours)}:${padZero(minutes)}:${padZero(secs)}`;
} else {
// MM:SS格式:小时自动转换为分钟(如120秒=02:00,3720秒=62:00)
const totalMinutes = Math.floor(seconds / 60);
return `${padZero(totalMinutes)}:${padZero(secs)}`;
}
}
/**
* 开始倒计时
* @param totalSeconds 总倒计时秒数(默认传当前剩余秒数)
*/
private startCountdown(totalSeconds: number = this.remainingSeconds): void {
// 清除已有定时器
this.clearTimer();
// 重置状态
this.remainingSeconds = totalSeconds;
this.isCounting = true;
this.btnDisabled = true;
// 创建定时器:每秒执行一次
this.timerId = setInterval(() => {
this.remainingSeconds--;
// 倒计时结束
if (this.remainingSeconds <= 0) {
this.clearTimer();
this.isCounting = false;
this.remainingSeconds = 0;
// 触发结束回调(自定义业务逻辑)
this.onCountdownFinish();
}
}, 1000);
}
/**
* 暂停倒计时
*/
private pauseCountdown(): void {
this.clearTimer();
this.isCounting = false;
}
/**
* 重置倒计时
*/
private resetCountdown(): void {
this.clearTimer();
this.remainingSeconds = 120; // 重置为初始值
this.isCounting = false;
this.btnDisabled = true;
}
/**
* 清除定时器(通用方法)
*/
private clearTimer(): void {
if (this.timerId !== -1) {
clearInterval(this.timerId);
this.timerId = -1;
}
}
/**
* 倒计时结束回调(自定义业务逻辑)
*/
private onCountdownFinish(): void {
console.log('倒计时结束:触发自定义业务逻辑');
// 示例1:启用按钮
this.btnDisabled = false;
// 示例2:弹窗提示(可根据需求扩展)
// promptAction.showToast({ message: '倒计时结束!' });
}
}
四、效果展示

更多关于HarmonyOS 鸿蒙Next中如何实现自定义倒计时功能?可支持自定义时间格式(HH:MM:SS/MM:SS)的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
学习了,厉害!,
如果对时间要求精准,应该用轮训,记录下开始时间戳,再定时计算过去了多久,这样就算退到后台,应用被挂起后,重新进时间也是准确的,直接setInterval会有时间差,越久偏差越大了,且不能退后台,
不过就简单计时没啥问题,
在HarmonyOS Next中,实现自定义倒计时功能需使用@ohos.worker创建后台任务。通过setInterval每秒更新剩余时间,计算时、分、秒。自定义时间格式可通过条件判断实现:检测格式字符串包含“HH”则显示小时,否则隐藏。使用Text组件显示格式化后的时间字符串,格式如${hh}:${mm}:${ss}或${mm}:${ss}。倒计时结束调用clearInterval停止任务。
在HarmonyOS Next中实现自定义倒计时功能,可以通过@State、@Link装饰器结合定时器与日期计算来实现,核心是管理剩余时间并格式化输出。
1. 核心实现方案:
- 使用
@State装饰器定义倒计时剩余总秒数totalSeconds和格式化后的时间字符串timeText。 - 在
aboutToAppear()中初始化倒计时,在aboutToDisappear()中清除定时器。 - 通过
setInterval启动每秒更新的定时器,在回调中减少totalSeconds并更新timeText。 - 倒计时结束时触发自定义回调(如启用按钮),并清除定时器。
2. 关键代码示例:
// 自定义时间格式化函数
private formatTime(seconds: number, format: string): string {
const hrs = Math.floor(seconds / 3600);
const mins = Math.floor((seconds % 3600) / 60);
const secs = seconds % 60;
if (format === 'HH:MM:SS') {
return `${hrs.toString().padStart(2, '0')}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
} else {
// MM:SS格式(自动处理小时部分)
const totalMins = Math.floor(seconds / 60);
const remainingSecs = seconds % 60;
return `${totalMins.toString().padStart(2, '0')}:${remainingSecs.toString().padStart(2, '0')}`;
}
}
// 倒计时逻辑
@State totalSeconds: number = 300; // 默认5分钟
@State timeText: string = '';
private timerId: number = 0;
aboutToAppear() {
this.startCountdown();
}
startCountdown() {
this.timerId = setInterval(() => {
if (this.totalSeconds > 0) {
this.totalSeconds--;
this.timeText = this.formatTime(this.totalSeconds, 'HH:MM:SS'); // 可配置格式
} else {
clearInterval(this.timerId);
this.onCountdownEnd(); // 触发结束回调
}
}, 1000);
}
onCountdownEnd() {
// 执行自定义业务逻辑,如启用按钮、弹出提示
// this.isButtonEnabled = true;
}
aboutToDisappear() {
clearInterval(this.timerId);
}
3. 自定义配置扩展:
- 通过
@Prop接收外部传入的初始时间、时间格式参数。 - 结束回调可通过自定义事件或函数参数暴露给父组件。
- 支持动态暂停/重启:通过状态变量控制定时器启停。
4. 多版本适配:
- 使用ArkTS语法,确保与HarmonyOS Next API完全兼容。
- 避免使用已废弃的API,如
getContext()相关操作需替换为当前版本推荐方式。 - 时间格式化使用纯TypeScript/JavaScript实现,不依赖额外资源包。
此方案通过状态驱动UI更新,符合HarmonyOS Next的声明式开发范式,能灵活适配不同时间格式和业务场景。

