yunshangxie/tuniao-ui/components/tn-count-down/tn-count-down.vue

315 lines
7.9 KiB
Vue
Raw Normal View History

2023-12-25 17:56:30 +08:00
<template>
<view class="tn-countdown-class tn-countdown">
<view
v-if="showDays && (hideZeroDay || (!hideZeroDay && d != '00'))"
class="tn-countdown__item"
:class="[backgroundColorClass]"
:style="[itemStyle]"
>
<view class="tn-countdown__item__time" :class="[fontColorClass]" :style="[letterStyle]">
{{ d }}
</view>
</view>
<view
v-if="showHours && (hideZeroDay || (!hideZeroDay && d != '00'))"
class="tn-countdown__separator"
:style="{
fontSize: separatorSize + 'rpx',
color: separatorColor,
paddingBottom: separator === 'en' ? '4rpx' : 0
}"
>
{{ separator === 'en' ? ':' : '天'}}
</view>
<view
v-if="showHours"
class="tn-countdown__item"
:class="[backgroundColorClass]"
:style="[itemStyle]"
>
<view class="tn-countdown__item__time" :class="[fontColorClass]" :style="[letterStyle]">
{{ h }}
</view>
</view>
<view
v-if="showMinutes"
class="tn-countdown__separator"
:style="{
fontSize: separatorSize + 'rpx',
color: separatorColor,
paddingBottom: separator === 'en' ? '4rpx' : 0
}"
>
{{ separator === 'en' ? ':' : '时'}}
</view>
<view
v-if="showMinutes"
class="tn-countdown__item"
:class="[backgroundColorClass]"
:style="[itemStyle]"
>
<view class="tn-countdown__item__time" :class="[fontColorClass]" :style="[letterStyle]">
{{ m }}
</view>
</view>
<view
v-if="showSeconds"
class="tn-countdown__separator"
:style="{
fontSize: separatorSize + 'rpx',
color: separatorColor,
paddingBottom: separator === 'en' ? '4rpx' : 0
}"
>
{{ separator === 'en' ? ':' : '分'}}
</view>
<view
v-if="showSeconds"
class="tn-countdown__item"
:class="[backgroundColorClass]"
:style="[itemStyle]"
>
<view class="tn-countdown__item__time" :class="[fontColorClass]" :style="[letterStyle]">
{{ s }}
</view>
</view>
<view
v-if="showSeconds && separator === 'cn'"
class="tn-countdown__separator"
:style="{
fontSize: separatorSize + 'rpx',
color: separatorColor,
paddingBottom: separator === 'en' ? '4rpx' : 0
}"
>
</view>
</view>
</template>
<script>
import componentsColorMixin from '../../libs/mixin/components_color.js'
export default {
name: 'tn-count-down',
mixins: [componentsColorMixin],
props: {
// 倒计时时间,秒作为单位
timestamp: {
type: Number,
default: 0
},
// 是否自动开始
autoplay: {
type: Boolean,
default: true
},
// 数字框高度
height: {
type: [String, Number],
default: 'auto'
},
// 分隔符类型
// en -> 使用英文的冒号 cn -> 使用中文进行分割
separator: {
type: String,
default: 'en'
},
// 分割符大小
separatorSize: {
type: Number,
default: 30
},
// 分隔符颜色
separatorColor: {
type: String,
default: '#080808'
},
// 是否显示边框
showBorder: {
type: Boolean,
default: false
},
// 边框颜色
borderColor: {
type: String,
default: '#080808'
},
// 是否显示秒
showSeconds: {
type: Boolean,
default: true
},
// 是否显示分
showMinutes: {
type: Boolean,
default: true
},
// 是否显示时
showHours: {
type: Boolean,
default: true
},
// 是否显示天
showDays: {
type: Boolean,
default: true
},
// 如果当天的部分为0时是否隐藏不显示
hideZeroDay: {
type: Boolean,
default: false
}
},
computed: {
// 倒计时item的样式
itemStyle() {
let style = {}
if (this.height) {
style.height = this.$tn.string.getLengthUnitValue(this.height)
style.width = style.height
}
if (this.showBorder) {
style.borderStyle = 'solid'
style.borderColor = this.borderColor
style.borderWidth = '1rpx'
}
style.backgroundColor = this.backgroundColorStyle || '#FFFFFF'
return style
},
// 倒计时数字样式
letterStyle() {
let style = {}
style.fontSize = this.fontSizeStyle || '30rpx'
style.color = this.fontColorStyle || '#080808'
return style
}
},
data() {
return {
d: '00',
h: '00',
m: '00',
s: '00',
// 定时器
timer: null,
// 记录倒计过程中变化的秒数
seconds: 0
}
},
watch: {
// 监听时间戳变化
timestamp(value) {
this.clearTimer()
this.start()
}
},
mounted() {
// 如果时自动倒计时,加载完成开始计时
this.autoplay && this.timestamp && this.start()
},
beforeDestroy() {
this.clearTimer()
},
methods: {
// 开始倒计时
start() {
// 避免可能出现的倒计时重叠情况
this.clearTimer()
if (this.timestamp <= 0) return
this.seconds = Number(this.timestamp)
this.formatTime(this.seconds)
this.timer = setInterval(() => {
this.seconds--
// 发出change事件
this.$emit('change', this.seconds)
if (this.seconds < 0) {
return this.end()
}
this.formatTime(this.seconds)
}, 1000)
},
// 格式化时间
formatTime(seconds) {
// 小于等于0的话结束倒计时
seconds <= 0 && this.end()
let [day, hour, minute, second] = [0, 0, 0, 0]
day = Math.floor(seconds / (60 * 60 * 24))
// 如果不显示天,则将天对应的小时计入到小时中
// 先把当前的hour计算出来供分和秒使用
hour = Math.floor(seconds / (60 * 60)) - (day * 24)
let showHour = null
if (this.showDays) {
showHour = hour
} else {
// 将天数对应的小时加入到时中进行显示
showHour = Math.floor(seconds / (60 * 60))
}
minute = Math.floor(seconds / 60) - (hour * 60) - (day * 24 * 60)
second = Math.floor(seconds) - (minute * 60) - (hour * 60 * 60) - (day * 24 * 60 * 60)
// 如果小于0在前面进行补0操作
showHour = this.$tn.number.formatNumberAddZero(showHour)
minute = this.$tn.number.formatNumberAddZero(minute)
second = this.$tn.number.formatNumberAddZero(second)
day = this.$tn.number.formatNumberAddZero(day)
this.d = day
this.h = showHour
this.m = minute
this.s = second
},
// 倒计时结束
end() {
this.clearTimer()
this.$emit('end')
},
// 清除倒计时
clearTimer() {
if (this.timer !== null) {
clearInterval(this.timer)
this.timer = null
}
}
}
}
</script>
<style lang="scss" scoped>
.tn-countdown {
/* #ifndef APP-NVUE */
display: inline-flex;
/* #endif */
align-items: center;
&__item {
box-sizing: content-box;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 2rpx;
border-radius: 6rpx;
white-space: nowrap;
transform: translateZ(0);
&__time {
margin: 0;
padding: 0;
line-height: 1;
}
}
&__separator {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 0 5rpx;
line-height: 1;
}
}
</style>