介绍
倒计时组件,支持自定义天、时、分、秒、毫秒的显示样式,可配置倒计时开始、结束、更新等回调事件。
链接
效果图
下载安装
在每个har/hsp模块中,通过ohpm工具下载安装库:
ohpm install @hzw/zcountdown
使用方法
@Component
struct Index {
build() {
Column() {
// 基础用法
CountdownView({
// 倒计时结束时间
endTime: systemDateTime.getTime() + 1000 * 60 * 60 * 24 * 3,
// 时间倒计时回调,回调剩余时间
updateTime: (time: number) => {
console.log(`${new Date(time)}`)
},
})
// 自定义后缀文本
CountdownView({
endTime: systemDateTime.getTime() + 1000 * 60 * 60 * 24 * 3,
suffixHour: "时",
suffixMinute: "分",
suffixSecond: "秒",
suffixMillisecond: "毫秒",
isShowMillisecond: true,
updateTime: (time: number) => {
console.log(`${new Date(time)}`)
},
})
// 自定义样式
CountdownView({
endTime: systemDateTime.getTime() + 1000 * 60 * 60 * 24 * 3,
started: true,
timeFontColor: Color.White,
timeStartBgColor: Color.Red,
timeEndBgColor: Color.Pink,
timeBgRadius: 10,
timeFontSize: 14,
timeWidth: 50,
timeHeight: 20,
suffixText: ":",
suffixFontColor: Color.Blue,
suffixFontSize: 14,
suffixWidth: 20,
dayFontColor: Color.Green,
dayFontSize: 14,
dayPrefix: "距离活动还有",
daySuffix: "天",
dayMargin: 10,
isShowDay: true,
isShowHour: true,
isShowMinute: true,
isShowSecond: true,
isShowMillisecond: true,
onStart: () => {
console.log("倒计时开始")
},
onEnd: () => {
console.log("倒计时结束")
},
updateTime: (time: number) => {
console.log(`${new Date(time)}`)
},
})
// 使用TextModifier自定义样式
CountdownView({
endTime: systemDateTime.getTime() + 1000 * 60 * 60 * 24 * 3,
dayPrefix: "离结束还有",
daySuffix: "日",
suffixHour: "时",
suffixMinute: "分",
suffixSecond: "秒",
dayPrefixModifier: new TextModifier().fontColor(Color.Red),
dayModifier: new TextModifier().fontColor(Color.White)
.backgroundColor(Color.Green).padding(4).margin(2).borderRadius(4),
daySuffixModifier: new TextModifier().fontColor(Color.Blue),
hourModifier: new TextModifier().fontColor(Color.White)
.backgroundColor(Color.Red).padding(4).margin(2).borderRadius(100).rotate({angle: 30}),
hourSuffixModifier: new TextModifier().fontColor(Color.Brown),
minuteModifier: new TextModifier().fontColor(Color.Black),
minuteSuffixModifier: new TextModifier().fontColor(Color.White)
.backgroundColor(Color.Orange).width(30).height(30).fontSize(18).margin(4).borderRadius(10),
secondModifier: new TextModifier().fontColor(Color.Pink),
secondSuffixModifier: new TextModifier().fontColor(Color.Red)
.visibility(Visibility.Visible),
updateTime: (time: number) => {
console.log(`${new Date(time)}`)
},
})
}
}
}
参数说明
参数名 | 类型 | 默认值 | 说明 |
---|---|---|---|
endTime | number | 0 | 倒计时结束时间戳(毫秒) |
started | boolean | true | 是否开始倒计时 |
timeFontColor | ResourceColor | Color.Black | 时间字体颜色 |
timeStartBgColor | ResourceColor | Color.Transparent | 时间背景渐变开始颜色 |
timeEndBgColor | ResourceColor | Color.Transparent | 时间背景渐变结束颜色 |
timeBgRadius | number | 0 | 时间背景圆角 |
timeFontSize | number | string | Resource | 14 | 时间字体大小 |
timeWidth | number | undefined | 时间宽度 |
timeHeight | number | undefined | 时间高度 |
suffixText | string | Resource | “:” | 分隔符文本 |
suffixHour | string | undefined | 小时后缀文本 |
suffixMinute | string | undefined | 分钟后缀文本 |
suffixSecond | string | undefined | 秒后缀文本 |
suffixMillisecond | string | undefined | 毫秒后缀文本 |
suffixFontColor | ResourceColor | Color.Black | 分隔符字体颜色 |
suffixFontSize | number | string | Resource | 14 | 分隔符字体大小 |
suffixWidth | number | undefined | 分隔符宽度 |
dayFontColor | ResourceColor | Color.Black | 天数字体颜色 |
dayFontSize | number | string | Resource | 14 | 天数字体大小 |
dayPrefix | string | “” | 天数前缀文本 |
daySuffix | string | “天” | 天数后缀文本 |
dayMargin | number | 0 | 天数右侧间距 |
isShowDay | boolean | true | 是否显示天数 |
isShowHour | boolean | true | 是否显示小时 |
isShowMinute | boolean | true | 是否显示分钟 |
isShowSecond | boolean | true | 是否显示秒数 |
isShowMillisecond | boolean | false | 是否显示毫秒 |
dayPrefixModifier | TextModifier | undefined | 自定义天数前缀样式 |
dayModifier | TextModifier | undefined | 自定义天数样式 |
daySuffixModifier | TextModifier | undefined | 自定义天数后缀样式 |
hourModifier | TextModifier | undefined | 自定义小时样式 |
hourSuffixModifier | TextModifier | undefined | 自定义小时后缀样式 |
minuteModifier | TextModifier | undefined | 自定义分钟样式 |
minuteSuffixModifier | TextModifier | undefined | 自定义分钟后缀样式 |
secondModifier | TextModifier | undefined | 自定义秒数样式 |
secondSuffixModifier | TextModifier | undefined | 自定义秒数后缀样式 |
millisecondModifier | TextModifier | undefined | 自定义毫秒样式 |
millisecondSuffixModifier | TextModifier | undefined | 自定义毫秒后缀样式 |
onStart | () => void | - | 倒计时开始回调 |
onEnd | () => void | - | 倒计时结束回调 |
updateTime | (time: number) => void | - | 倒计时更新回调,参数为剩余时间(毫秒) |
源码
import { systemDateTime } from '@kit.BasicServicesKit'
import { TextModifier } from '@kit.ArkUI'
/**
* @author: HHBin
* @date: 2025/1/2
* @desc: 时间倒计时控件
*/
@ComponentV2
export struct CountdownView {
/**
* 倒计时结束时间
*/
@Param endTime: number = 0
/**
* 是否开始倒计时
*/
@Param started: boolean = true
/**
* 时间字体颜色
*/
@Param timeFontColor: ResourceColor = Color.Black;
/**
* 时间背景开始颜色
*/
@Param timeStartBgColor: ResourceColor = Color.Transparent;
/**
* 时间背景结束颜色
*/
@Param timeEndBgColor: ResourceColor = Color.Transparent;
/**
* 时间背景圆角
*/
@Param timeBgRadius: number = 0;
/**
* 时间字体大小
*/
@Param timeFontSize: number | string | Resource = 14;
/**
* 时间宽度
*/
@Param timeWidth: number | undefined = undefined;
/**
* 时间高度
*/
@Param timeHeight: number | undefined = undefined;
/**
* 后缀文本
*/
@Param suffixText: string | Resource = ":";
/**
* 时后缀
*/
@Param suffixHour: string | undefined = undefined
/**
* 分后缀
*/
@Param suffixMinute: string | undefined = undefined
/**
* 秒后缀
*/
@Param suffixSecond: string | undefined = undefined
/**
* 毫秒后缀
*/
@Param suffixMillisecond: string | undefined = undefined
/**
* 后缀颜色
*/
@Param suffixFontColor: ResourceColor = Color.Black;
/**
* 后缀字体大小
*/
@Param suffixFontSize: number | string | Resource = 14;
/**
* 后缀字体宽度
*/
@Param suffixWidth: number | undefined = undefined;
/**
* 天颜色
*/
@Param dayFontColor: ResourceColor = Color.Black;
/**
* 天字体大小
*/
@Param dayFontSize: number | string | Resource = 14;
/**
* 天前缀
*/
@Param dayPrefix: string = ""
/**
* 天后缀
*/
@Param daySuffix: string = "天"
/**
* 天间隔
*/
@Param dayMargin: number = 0
/**
* 是否显示天
*/
@Param isShowDay: boolean = true
/**
* 是否显示小时
*/
@Param isShowHour: boolean = true
/**
* 是否显示分钟
*/
@Param isShowMinute: boolean = true
/**
* 是否显示秒
*/
@Param isShowSecond: boolean = true
/**
* 是否显示毫秒
*/
@Param isShowMillisecond: boolean = false
/**
* 自定义日前缀样式
*/
@Param dayPrefixModifier: TextModifier | undefined = undefined
/**
* 自定义天样式
*/
@Param dayModifier: TextModifier | undefined = undefined
/**
* 自定义日后缀样式
*/
@Param daySuffixModifier: TextModifier | undefined = undefined
/**
* 自定义时样式
*/
@Param hourModifier: TextModifier | undefined = undefined
/**
* 自定义时后缀样式
*/
@Param hourSuffixModifier: TextModifier | undefined = undefined
/**
* 自定义分样式
*/
@Param minuteModifier: TextModifier | undefined = undefined
/**
* 自定义分后缀样式
*/
@Param minuteSuffixModifier: TextModifier | undefined = undefined
/**
* 自定义秒样式
*/
@Param secondModifier: TextModifier | undefined = undefined
/**
* 自定义秒后缀样式
*/
@Param secondSuffixModifier: TextModifier | undefined = undefined
/**
* 自定义毫秒样式
*/
@Param millisecondModifier: TextModifier | undefined = undefined
/**
* 自定义毫秒后缀样式
*/
@Param millisecondSuffixModifier: TextModifier | undefined = undefined
/**
* 时间倒计时开始回调
*/
@Event onStart?: () => void
/**
* 时间倒计时结束回调
*/
@Event onEnd?: () => void
/**
* 时间倒计时回调,回调剩余时间
*/
@Event updateTime?: (time: number) => void
@Event $started: (val: boolean) => void = () => {
}
@Computed
get realEndTime(): number {
return this.endTime > 1e10 ? this.endTime : this.endTime * 1000
}
@Monitor("started")
onStartedChange() {
if (this.started) {
this.startInterval()
} else {
this.stopInterval()
}
}
@Local private day: number = 0
@Local private hour: number = 0
@Local private minute: number = 0
@Local private second: number = 0
@Local private millisecond: number = 0
private left: number = 0
private intervalId?: number
aboutToAppear(): void {
if (this.started) {
this.startInterval()
}
}
aboutToDisappear(): void {
this.stopInterval()
}
startInterval() {
this.stopInterval()
this.onStart?.()
this.intervalId = setInterval(() => {
this.left = this.realEndTime - systemDateTime.getTime()
if (this.left <= 0) {
this.onEnd?.()
this.$started(false)
this.stopInterval()
return
}
this.day = this.getLeftDay(this.left)
this.hour = this.getLeftHour(this.left)
this.minute = this.getLeftMinute(this.left)
this.second = this.getLeftSecond(this.left)
this.millisecond = this.getLeftMillisecond(this.left)
this.updateTime?.(this.left)
}, this.isShowMillisecond ? 10 : 500);
}
stopInterval() {
if (this.intervalId) {
clearInterval(this.intervalId)
}
this.intervalId = undefined
}
build() {
Row() {
Text(`${this.dayPrefix}`)
.fontSize(this.dayFontSize)
.fontColor(this.dayFontColor)
.visibility(this.isShowDay ? Visibility.Visible : Visibility.None)
.textAlign(TextAlign.Center)
.attributeModifier(this.dayPrefixModifier)
Text(`${this.day.toString()}`)
.fontSize(this.dayFontSize)
.fontColor(this.dayFontColor)
.visibility(this.isShowDay ? Visibility.Visible : Visibility.None)
.textAlign(TextAlign.Center)
.attributeModifier(this.dayModifier)
Text(`${this.daySuffix}`)
.fontSize(this.dayFontSize)
.fontColor(this.dayFontColor)
.visibility(this.isShowDay ? Visibility.Visible : Visibility.None)
.textAlign(TextAlign.Center)
.margin({ right: this.dayMargin })
.attributeModifier(this.daySuffixModifier)
Text(`${this.hour.toString().padStart(2, '0')}`)
.fontSize(this.timeFontSize)
.fontColor(this.timeFontColor)
.visibility(this.isShowHour ? Visibility.Visible : Visibility.None)
.width(this.timeWidth)
.height(this.timeHeight)
.textAlign(TextAlign.Center)
.linearGradient({
angle: 90,
colors: [[this.timeStartBgColor, 0.0], [this.timeEndBgColor, 1]]
})
.borderRadius(this.timeBgRadius)
.attributeModifier(this.hourModifier)
Text(this.suffixHour ?? this.suffixText)
.fontSize(this.suffixFontSize)
.fontColor(this.suffixFontColor)
.visibility(this.isShowHour && this.isShowMinute ? Visibility.Visible : Visibility.None)
.width(this.suffixWidth)
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Bold)
.attributeModifier(this.hourSuffixModifier)
Text(`${this.minute.toString().padStart(2, '0')}`)
.fontSize(this.timeFontSize)
.fontColor(this.timeFontColor)
.visibility(this.isShowMinute ? Visibility.Visible : Visibility.None)
.width(this.timeWidth)
.height(this.timeHeight)
.textAlign(TextAlign.Center)
.linearGradient({
angle: 90,
colors: [[this.timeStartBgColor, 0.0], [this.timeEndBgColor, 1]]
})
.borderRadius(this.timeBgRadius)
.attributeModifier(this.minuteModifier)
Text(this.suffixMinute ?? this.suffixText)
.fontSize(this.suffixFontSize)
.fontColor(this.suffixFontColor)
.visibility(this.isShowMinute && this.isShowSecond ? Visibility.Visible : Visibility.None)
.width(this.suffixWidth)
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Bold)
.attributeModifier(this.minuteSuffixModifier)
Text(`${this.second.toString().padStart(2, '0')}`)
.fontSize(this.timeFontSize)
.fontColor(this.timeFontColor)
.visibility(this.isShowSecond ? Visibility.Visible : Visibility.None)
.width(this.timeWidth)
.height(this.timeHeight)
.textAlign(TextAlign.Center)
.linearGradient({
angle: 90,
colors: [[this.timeStartBgColor, 0.0], [this.timeEndBgColor, 1]]
})
.borderRadius(this.timeBgRadius)
.attributeModifier(this.secondModifier)
Text(this.suffixSecond ?? this.suffixText)
.fontSize(this.suffixFontSize)
.fontColor(this.suffixFontColor)
.visibility(this.isShowSecond && this.isShowMillisecond ? Visibility.Visible : Visibility.None)
.width(this.suffixWidth)
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Bold)
.attributeModifier(this.secondSuffixModifier)
Text(`${this.millisecond.toString().padStart(3, '0')}`)
.fontSize(this.timeFontSize)
.fontColor(this.timeFontColor)
.visibility(this.isShowMillisecond ? Visibility.Visible : Visibility.None)
.width(this.timeWidth)
.height(this.timeHeight)
.textAlign(TextAlign.Center)
.linearGradient({
angle: 90,
colors: [[this.timeStartBgColor, 0.0], [this.timeEndBgColor, 1]]
})
.borderRadius(this.timeBgRadius)
.attributeModifier(this.millisecondModifier)
Text(this.suffixMillisecond)
.fontSize(this.suffixFontSize)
.fontColor(this.suffixFontColor)
.visibility(this.isShowMillisecond && this.isShowMillisecond ? Visibility.Visible : Visibility.None)
.width(this.suffixWidth)
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Bold)
.attributeModifier(this.millisecondSuffixModifier)
}
.alignItems(VerticalAlign.Center)
}
/**
* 获取剩余天数
*/
private getLeftDay(time: number): number {
return Math.floor(time / (1000 * 24 * 60 * 60))
}
/**
* 获取剩余小时
*/
private getLeftHour(time: number): number {
return Math.floor((time - this.getLeftDay(time) * (1000 * 24 * 60 * 60)) / (1000 * 60 * 60))
}
/**
* 获取剩余分钟
*/
private getLeftMinute(time: number): number {
return Math.floor((time - this.getLeftDay(time) * (1000 * 24 * 60 * 60) -
this.getLeftHour(time) * (1000 * 60 * 60)) / (1000 * 60))
}
/**
* 获取剩余秒数
*/
private getLeftSecond(time: number): number {
return Math.floor((time - this.getLeftDay(time) * (1000 * 24 * 60 * 60) -
this.getLeftHour(time) * (1000 * 60 * 60) - this.getLeftMinute(time) * (1000 * 60)) / 1000)
}
/**
* 获取剩余毫秒数
*/
private getLeftMillisecond(time: number): number {
return time % 1000
}
}