2025-07-22 18:31:50 +08:00

336 lines
7.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="tui-countdown-box">
<view class="tui-countdown-item" :style="{ background: backgroundColor, borderColor: borderColor, width: getWidth(d, width) + 'rpx', height: height + 'rpx' }" v-if="days">
<view class="tui-countdown-time" :class="[scale ? 'tui-countdown-scale' : '']" :style="{ fontSize: size + 'rpx', color: color, lineHeight: height + 'rpx' }">
{{ d }}
</view>
</view>
<view
class="tui-countdown-colon"
:class="{ 'tui-colon-pad': borderColor == 'transparent' }"
:style="{ fontSize: colonSize + 'rpx', color: colonColor }"
v-if="days"
>
{{ isColon ? ':' : '天' }}
</view>
<view class="tui-countdown-item" :style="{ background: backgroundColor, borderColor: borderColor, width: getWidth(h, width) + 'rpx', height: height + 'rpx' }" v-if="hours">
<view class="tui-countdown-time" :class="[scale ? 'tui-countdown-scale' : '']" :style="{ fontSize: size + 'rpx', color: color, lineHeight: height + 'rpx' }">
{{ h }}
</view>
</view>
<view
class="tui-countdown-colon"
:class="{ 'tui-colon-pad': borderColor == 'transparent' }"
:style="{ fontSize: colonSize + 'rpx', color: colonColor }"
v-if="hours"
>
{{ isColon ? ':' : '时' }}
</view>
<view
class="tui-countdown-item"
:style="{ background: backgroundColor, borderColor: borderColor, width: getWidth(i, width) + 'rpx', height: height + 'rpx' }"
v-if="minutes"
>
<view class="tui-countdown-time" :class="[scale ? 'tui-countdown-scale' : '']" :style="{ fontSize: size + 'rpx', color: color, lineHeight: height + 'rpx' }">
{{ i }}
</view>
</view>
<view
class="tui-countdown-colon"
:class="{ 'tui-colon-pad': borderColor == 'transparent' }"
:style="{ fontSize: colonSize + 'rpx', color: colonColor }"
v-if="minutes"
>
{{ isColon ? ':' : '分' }}
</view>
<view
class="tui-countdown-item"
:style="{ background: backgroundColor, borderColor: borderColor, width: getWidth(s, width) + 'rpx', height: height + 'rpx' }"
v-if="seconds"
>
<view class="tui-countdown-time" :class="[scale ? 'tui-countdown-scale' : '']" :style="{ fontSize: size + 'rpx', color: color, lineHeight: height + 'rpx' }">
{{ s }}
</view>
</view>
<view
class="tui-countdown-colon"
:class="{ 'tui-colon-pad': borderColor == 'transparent' }"
:style="{ fontSize: colonSize + 'rpx', color: colonColor }"
v-if="seconds && !isColon"
>
{{ unitEn ? 's' : '秒' }}
</view>
<view class="tui-countdown-colon" :style="{ lineHeight: colonSize + 'rpx', fontSize: colonSize + 'rpx', color: colonColor }" v-if="seconds && isMs && isColon">.</view>
<view
class="tui-countdown__ms"
:style="{
background: backgroundColor,
borderColor: borderColor,
fontSize: msSize + 'rpx',
color: msColor,
height: height + 'rpx',
width: msWidth > 0 ? msWidth + 'rpx' : 'auto'
}"
v-if="seconds && isMs"
>
<view :class="{ 'tui-ms__list': ani }">
<view class="tui-ms__item" :style="{ height: height + 'rpx' }" v-for="(item, index) in ms" :key="index">
<view :class="[scale ? 'tui-countdown-scale' : '']">{{item}}</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'tuiCountdown',
props: {
//数字框宽度
width: {
type: Number,
default: 32
},
//数字框高度
height: {
type: Number,
default: 32
},
//数字框border颜色
borderColor: {
type: String,
default: '#333'
},
//数字框背景颜色
backgroundColor: {
type: String,
default: '#fff'
},
//数字框字体大小
size: {
type: Number,
default: 24
},
//数字框字体颜色
color: {
type: String,
default: '#333'
},
//是否缩放 0.9
scale: {
type: Boolean,
default: false
},
//冒号大小
colonSize: {
type: Number,
default: 28
},
//冒号颜色
colonColor: {
type: String,
default: '#333'
},
//剩余时间 (单位:秒)
time: {
type: Number,
default: 0
},
//是否包含天
days: {
type: Boolean,
default: false
},
//是否包含小时
hours: {
type: Boolean,
default: true
},
//是否包含分钟
minutes: {
type: Boolean,
default: true
},
//是否包含秒
seconds: {
type: Boolean,
default: true
},
//单位用英文缩写表示 仅seconds秒数有效
unitEn: {
type: Boolean,
default: false
},
//是否展示为冒号,false为文字
isColon: {
type: Boolean,
default: true
},
//是否返回剩余时间
returnTime: {
type: Boolean,
default: false
},
//是否显示毫秒
isMs: {
type: Boolean,
default: false
},
msWidth: {
type: Number,
default: 32
},
msSize: {
type: Number,
default: 24
},
msColor: {
type: String,
default: '#333'
}
},
watch: {
time(val) {
this.clearTimer();
this.doLoop();
}
},
data() {
return {
countdown: null,
d: '0',
h: '00',
i: '00',
s: '00',
//此处若从9到1结束需要特殊处理
ms: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
ani: false
};
},
created() {
this.clearTimer();
this.doLoop();
},
beforeDestroy() {
this.clearTimer();
},
methods: {
getWidth: function(num, width) {
return num > 99 ? (width / 2) * num.toString().length : width;
},
clearTimer() {
clearInterval(this.countdown);
this.countdown = null;
},
endOfTime() {
this.ani = false;
this.clearTimer();
this.$emit('end', {});
},
doLoop: function() {
let seconds = this.time || 0;
this.ani = true;
this.countDown(seconds);
this.countdown = setInterval(() => {
seconds--;
if (seconds < 0) {
this.endOfTime();
return;
}
this.countDown(seconds);
if (this.returnTime) {
this.$emit('time', { seconds: seconds });
}
}, 1000);
},
countDown(seconds) {
let [day, hour, minute, second] = [0, 0, 0, 0];
if (seconds > 0) {
day = this.days ? Math.floor(seconds / (60 * 60 * 24)) : 0;
hour = this.hours ? Math.floor(seconds / (60 * 60)) - day * 24 : 0;
minute = this.minutes ? Math.floor(seconds / 60) - hour * 60 - day * 24 * 60 : 0;
second = Math.floor(seconds) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60;
} else {
this.endOfTime();
}
hour = hour < 10 ? '0' + hour : hour;
minute = minute < 10 ? '0' + minute : minute;
second = second < 10 ? '0' + second : second;
this.d = day;
this.h = hour;
this.i = minute;
this.s = second;
}
}
};
</script>
<style scoped>
.tui-countdown-box {
display: flex;
align-items: center;
}
.tui-countdown-box {
display: flex;
align-items: center;
}
.tui-countdown-item {
border: 1rpx solid;
display: flex;
align-items: center;
justify-content: center;
border-radius: 6rpx;
white-space: nowrap;
transform: translateZ(0);
}
.tui-countdown-time {
margin: 0;
padding: 0;
}
.tui-countdown-colon {
display: flex;
justify-content: center;
padding: 0 5rpx;
}
.tui-colon-pad {
padding: 0 !important;
}
.tui-countdown-scale {
transform: scale(0.9);
transform-origin: center center;
}
.tui-countdown__ms {
border: 1rpx solid;
overflow: hidden;
border-radius: 6rpx;
}
/*ms使用css3代替js频繁更新操作性能优化*/
.tui-ms__list {
animation: loop 1s steps(10) infinite;
}
@keyframes loop {
from {
transform: translateY(0);
}
to {
transform: translateY(-100%);
}
}
.tui-ms__item {
display: flex;
align-items: center;
justify-content: center;
}
</style>