倒计时组件主要用于展示促销商品剩余活动时间、发送短信验证等待时间等场景。倒计时一般具有如下能力:
倒计时(countdown)组件结构分为数字和分隔符两部分。一般来说,数字表示倒计时的天、时、分、秒;分隔符用于分隔数字,常见的分隔符为文字分隔符(天、时、分、秒)和冒号分隔符。布局结构如下图:

布局代码如下:
<text>一般用法</text>
<div class="example-body">
<countdown class="countdown" day="{{this.day}}" hour="{{this.hour}}" minute="{{this.minute}}" second="{{this.second}}" splitor-color="#007AFF" border-width="{{3}}" border-style="dotted" border-color="#007AFF"></countdown>
</div>
倒计时整体外观都是通用的,但是内部具体的样式有区别,在设计的时候,不能把内部样式固定,否则一旦倒计时的UI有变化,会导致子组件也要修改,违背了对外开源的初衷。
<template>
<div class="countdown">
<text if="{{this.showDay}}" style="borderColor: {{this.borderColor}}; color: {{this.color}}; backgroundColor: {{this.backgroundColor}};border-width:{{this.borderWidth}};border-style:{{this.borderStyle}};" class="countdown__number">{{ d }}</text>
<text if="{{this.showDay}}" style="color: {{this.splitorColor}}" class="countdown__splitor">天</text>
<text style="borderColor: {{this.borderColor}}; color: {{this.color}}; backgroundColor: {{this.backgroundColor}};border-width:{{this.borderWidth}};border-style:{{this.borderStyle}}" class="countdown__number">{{ h }}</text>
<text style="color: {{this.splitorColor}}" class="countdown__splitor">{{ showColon ? ":" : "时" }}</text>
<text style="borderColor: {{this.borderColor}}; color: {{this.color}}; backgroundColor: {{this.backgroundColor}};border-width:{{this.borderWidth}};border-style:{{this.borderStyle}}" class="countdown__number">{{ i }}</text>
<text style="color: {{this.splitorColor}}" class="countdown__splitor">{{ showColon ? ":" : "分" }}</text>
<text style="borderColor: {{this.borderColor}};color: {{this.color}}; backgroundColor: {{this.backgroundColor}};border-width:{{this.borderWidth}};border-style:{{this.borderStyle}}" class="countdown__number">{{ s }}</text>
<text if="{{!showColon}}" style="color: {{this.splitorColor}}" class="countdown__splitor">秒</text>
</div>
</template>
属性 |
类型 |
默认值 |
描述 |
|---|---|---|---|
day |
Number |
0 |
倒计时的天。 |
hour |
Number |
0 |
倒计时的小时。 |
minute |
Number |
0 |
倒计时的分钟。 |
second |
Number |
0 |
倒计时的秒。 |
delay |
Number |
0 |
倒计时延迟时间,单位:秒。 |
showDay |
Boolean |
true |
是否显示天数。 |
showColon |
Boolean |
true |
是否以冒号为分隔符。 |
color |
String |
#000000 |
文字的颜色。 |
splitorColor |
String |
#000000 |
分隔符的颜色。 |
backgroundColor |
String |
#FFFFFF |
文字的背景色。 |
borderWidth |
Number |
0 |
文字边框的宽度。 |
borderStyle |
String |
solid |
文字边框的样式。 |
borderColor |
String |
#000000 |
文字边框的颜色。 |
事件名称 |
参数 |
描述 |
|---|---|---|
timeup |
无 |
倒计时结束的回调事件。 |
.countdown__splitor {
display: flex;
justify-content: center;
line-height: 48px;
padding: 5px;
}
.countdown__number {
display: flex;
justify-content: center;
align-items: center;
width: 52px;
height: 48px;
line-height: 48px;
margin: 5px;
text-align: center;
}
toSeconds(timestamp, day, hours, minutes, seconds) {
if (timestamp) {
return timestamp - parseInt(new Date().getTime() / 1000, 10)
}
return day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds
}, countDown() {
let seconds = this.seconds
let [day, hour, minute, second] = [0, 0, 0, 0]
if (seconds > 0) {
day = Math.floor(seconds / (60 * 60 * 24))
hour = Math.floor(seconds / (60 * 60)) - (day * 24)
minute = Math.floor(seconds / 60) - (day * 24 * 60) - (hour * 60)
second = Math.floor(seconds) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60)
} else {
this.timeUp()
}
if (day < 10) {
day = '0' + day
}
if (hour < 10) {
hour = '0' + hour
}
if (minute < 10) {
minute = '0' + minute
}
if (second < 10) {
second = '0' + second
}
this.d = day
this.h = hour
this.i = minute
this.s = second
}, props: {
day: {
type: Number,
default: 0
},
hour: {
type: Number,
default: 0
},
minute: {
type: Number,
default: 0
},
second: {
type: Number,
default: 0
}
},
onInit() {
this.$watch('day', 'changeFlag')
this.$watch('hour', 'changeFlag')
this.$watch('minute', 'changeFlag')
this.$watch('second', 'changeFlag')
}, <text>倒计时触发回调事件</text>
<div class="example-body">
<countdown class="countdown" show-day="{{false}}" second="{{this.second}}" @timeup="timeup"></countdown>
</div> timeup() {
prompt.showToast({
message: '时间到'
})
}, timeUp() {
clearInterval(this.timer)
this.$emit('timeup')
}, 倒计时countdown.ux代码:
<template>
<div class="countdown">
<text if="{{this.showDay}}" style="borderColor: {{this.borderColor}}; color: {{this.color}}; backgroundColor: {{this.backgroundColor}};border-width:{{this.borderWidth}};border-style:{{this.borderStyle}};" class="countdown__number">{{ d }}</text>
<text if="{{this.showDay}}" style="color: {{this.splitorColor}}" class="countdown__splitor">天</text>
<text style="borderColor: {{this.borderColor}}; color: {{this.color}}; backgroundColor: {{this.backgroundColor}};border-width:{{this.borderWidth}};border-style:{{this.borderStyle}}" class="countdown__number">{{ h }}</text>
<text style="color: {{this.splitorColor}}" class="countdown__splitor">{{ showColon ? ":" : "时" }}</text>
<text style="borderColor: {{this.borderColor}}; color: {{this.color}}; backgroundColor: {{this.backgroundColor}};border-width:{{this.borderWidth}};border-style:{{this.borderStyle}}" class="countdown__number">{{ i }}</text>
<text style="color: {{this.splitorColor}}" class="countdown__splitor">{{ showColon ? ":" : "分" }}</text>
<text style="borderColor: {{this.borderColor}};color: {{this.color}}; backgroundColor: {{this.backgroundColor}};border-width:{{this.borderWidth}};border-style:{{this.borderStyle}}" class="countdown__number">{{ s }}</text>
<text if="{{!showColon}}" style="color: {{this.splitorColor}}" class="countdown__splitor">秒</text>
</div>
</template>
<script>
/**
* Countdown 倒计时
* @description 倒计时组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=25
* @property {String} backgroundColor 背景色
* @property {String} color 文字颜色
* @property {Number} day 天数
* @property {Number} hour 小时
* @property {Number} minute 分钟
* @property {Number} second 秒
* @property {Number} timestamp 时间戳
* @property {Boolean} showDay = [true|false] 是否显示天数
* @property {Boolean} showColon = [true|false] 是否以冒号为分隔符
* @property {String} splitorColor 分割符号颜色
* @event {Function} timeup 倒计时时间到触发事件
* @example <countdown :day="1" :hour="1" :minute="12" :second="40"></countdown>
*/
export default {
props: {
day: {
type: Number,
default: 0
},
hour: {
type: Number,
default: 0
},
minute: {
type: Number,
default: 0
},
second: {
type: Number,
default: 0
},
showDay: {
type: Boolean,
default: true
},
showColon: {
type: Boolean,
default: true
},
delay: {
type: Number,
default: 0
},
backgroundColor: {
type: String,
default: '#FFFFFF'
},
color: {
type: String,
default: '#000000'
},
splitorColor: {
type: String,
default: '#000000'
},
borderWidth: {
type: Number,
default: 0
},
borderStyle: {
type: String,
default: 'solid'
},
borderColor: {
type: String,
default: '#000000'
},
timestamp: {
type: Number,
default: 0
}
},
data: {
timer: null,
syncFlag: true,
d: '00',
h: '00',
i: '00',
s: '00',
leftTime: 0,
seconds: 0
},
onInit() {
this.$watch('day', 'changeFlag')
this.$watch('hour', 'changeFlag')
this.$watch('minute', 'changeFlag')
this.$watch('second', 'changeFlag')
this.$watch('delay', 'delaytChange')
setTimeout(() => {
this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)
this.countDown()
if (this.syncFlag === true) {
this.startData();
this.syncFlag = false
}
}, 50);
setInterval(() => {
if (this.syncFlag === true) {
this.startData();
this.syncFlag = false
}
}, 1000);
},
onDestroy() {
clearInterval(this.timer)
},
toSeconds(timestamp, day, hours, minutes, seconds) {
if (timestamp) {
return timestamp - parseInt(new Date().getTime() / 1000, 10)
}
return day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds
},
timeUp() {
clearInterval(this.timer)
this.$emit('timeup')
},
countDown() {
//console.log("seconds = " + this.seconds)
let seconds = this.seconds
let [day, hour, minute, second] = [0, 0, 0, 0]
if (seconds > 0) {
day = Math.floor(seconds / (60 * 60 * 24))
hour = Math.floor(seconds / (60 * 60)) - (day * 24)
minute = Math.floor(seconds / 60) - (day * 24 * 60) - (hour * 60)
second = Math.floor(seconds) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60)
} else {
this.timeUp()
}
if (day < 10) {
day = '0' + day
}
if (hour < 10) {
hour = '0' + hour
}
if (minute < 10) {
minute = '0' + minute
}
if (second < 10) {
second = '0' + second
}
this.d = day
this.h = hour
this.i = minute
this.s = second
},
startData() {
console.log("startData")
this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)
if (this.seconds <= 0) {
return
}
this.countDown()
this.timer = setInterval(() => {
this.seconds--
if (this.seconds < 0) {
this.timeUp()
return
}
this.countDown()
}, 1000)
},
changeFlag() {
console.log("day = " + this.day + ", hour = " + this.hour + ", minute = " + this.minute + ", second = " + this.second);
},
delaytChange(newValue, oldValue) {
console.log("newValue = " + newValue + ", oldValue = " + oldValue)
if (newValue) {
this.syncFlag = false
setTimeout(() => {
this.syncFlag = true
}, (newValue - 1) * 1000);
}
else {
console.error("The delay value must be greater than 0.");
return
}
}
}
</script>
<style>
.countdown {
display: flex;
flex-direction: row;
padding: 2px 0;
height: 50px;
align-items: center;
}
.countdown__splitor {
display: flex;
justify-content: center;
line-height: 48px;
padding: 5px;
}
.countdown__number {
display: flex;
justify-content: center;
align-items: center;
width: 52px;
height: 48px;
line-height: 48px;
margin: 5px;
text-align: center;
}
</style>
页面hello.ux代码:
<import name="countdown" src="../Countdown/countdown"></import>
<template>
<div class="container">
<text class="example-info">倒计时组件主要用于促销商品剩余时间,发送短信验证等待时间等场景</text>
<text>一般用法</text>
<div class="example-body">
<countdown class="countdown" day="{{this.day}}" hour="{{this.hour}}" minute="{{this.minute}}" second="{{this.second}}" splitor-color="#007AFF" border-width="{{3}}" border-style="dotted" border-color="#007AFF"></countdown>
</div>
<text>延时5秒开始</text>
<div class="example-body">
<countdown class="countdown" delay="{{this.delay}}" day="{{this.day}}" hour="{{this.hour}}" minute="{{this.minute}}" second="{{this.second}}"></countdown>
</div>
<text>不显示天数,冒号分隔符</text>
<div class="example-body">
<countdown class="countdown" show-day="{{false}}" hour="{{this.hour}}" minute="{{this.minute}}" second="{{this.second}}"></countdown>
</div>
<text>文字分隔符</text>
<div class="example-body">
<countdown class="countdown" minute="{{this.minute}}" second="{{this.second}}" show-colon="{{false}}"></countdown>
</div>
<text>修改背景色</text>
<div class="example-body">
<countdown class="countdown" day="{{this.day}}" hour="{{this.hour}}" minute="{{this.minute}}" second="{{this.second}}" color="#FFFFFF" background-color="#007AFF" border-color="#efeff4"></countdown>
</div>
<text>倒计时触发回调事件</text>
<div class="example-body">
<countdown class="countdown" show-day="{{false}}" second="{{this.second}}" @timeup="timeup"></countdown>
</div>
</div>
</template>
<script>
import prompt from '@system.prompt';
export default {
data() {
return {
delay: 0,
day: 0,
hour: 0,
minute: 0,
second: 0,
timestamp: 0
}
},
onShow: function () {
console.log("开始倒计时");
this.day = 2
this.hour = 2
this.minute = 12
this.second = 10
this.delay = 5
},
timeup() {
prompt.showToast({
message: '时间到'
})
},
}
</script>
<style>
.container {
display: flex;
flex-direction: column;
background-color: #efeff4;
}
text {
font-size: 30px;
line-height: 80px;
}
.example-info {
padding: 15px;
color: #3b4144;
background-color: #ffffff;
}
.example {
padding: 0 15px;
}
.example-body {
flex-direction: column;
padding: 15px;
background-color: #ffffff;
height: 100px;
}
.countdown {
height: 100px;
}
</style>