163 lines
4.8 KiB
Vue
163 lines
4.8 KiB
Vue
<template>
|
|
<div class="countdown-wrapper" style="width: 100%">
|
|
<template v-if="isNotStarted">
|
|
<view class="fl_box fl_nowarp fl_justbet" style="width: 100%">
|
|
<view class="fl_box">
|
|
<span class="colon">距离开始还剩</span>
|
|
<div class="time-block">{{ days }}</div>
|
|
<span class="colon">天</span>
|
|
</view>
|
|
<view style="color: #ff881a">待开始</view>
|
|
</view>
|
|
</template>
|
|
|
|
<template v-else-if="isEnd">
|
|
<view class="fl_box fl_nowarp fl_justbet" style="width: 100%">
|
|
<view class="fl_box">
|
|
<span class="colon hui">距离结束还剩</span>
|
|
<div class="time-block huibg">00</div>
|
|
<span class="colon hui">:</span>
|
|
<div class="time-block huibg">00</div>
|
|
<span class="colon hui">:</span>
|
|
<div class="time-block huibg">00</div>
|
|
</view>
|
|
<view class="hui">已结束</view>
|
|
</view>
|
|
</template>
|
|
|
|
<template v-else>
|
|
<template v-if="showDays">
|
|
<view class="fl_box fl_nowarp fl_justbet" style="width: 100%">
|
|
<view class="fl_box">
|
|
<span class="colon">距离结束还剩</span>
|
|
<div class="time-block">{{ days }}</div>
|
|
<span class="colon">天</span>
|
|
</view>
|
|
<view style="color: #18a14f">进行中</view>
|
|
</view>
|
|
</template>
|
|
<template v-else>
|
|
<view class="fl_box fl_nowarp fl_justbet" style="width: 100%">
|
|
<view class="fl_box">
|
|
<span class="colon">距离结束还剩</span>
|
|
<div class="time-block">{{ hours }}</div>
|
|
<span class="colon">:</span>
|
|
<div class="time-block">{{ minutes }}</div>
|
|
<span class="colon">:</span>
|
|
<div class="time-block">{{ seconds }}</div>
|
|
</view>
|
|
<view style="color: #18a14f">进行中</view>
|
|
</view>
|
|
</template>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
|
|
|
const props = defineProps({
|
|
startTime: { type: [String, Number, Date], required: true },
|
|
endTime: { type: [String, Number, Date], required: true },
|
|
interval: { type: Number, default: 1000 },
|
|
});
|
|
|
|
const now = ref(Date.now());
|
|
let timer = null;
|
|
|
|
const startTimestamp = computed(() => new Date(props.startTime).getTime());
|
|
const endTimestamp = computed(() => new Date(props.endTime).getTime());
|
|
|
|
const isEnd = computed(() => now.value >= endTimestamp.value);
|
|
const isNotStarted = computed(() => now.value < startTimestamp.value);
|
|
|
|
const targetTimestamp = computed(() => {
|
|
if (isNotStarted.value) return startTimestamp.value;
|
|
if (!isEnd.value) return endTimestamp.value;
|
|
return now.value;
|
|
});
|
|
|
|
const remainingMs = computed(() => Math.max(0, targetTimestamp.value - now.value));
|
|
const secondsTotal = computed(() => Math.floor(remainingMs.value / 1000));
|
|
|
|
const showDays = computed(() => secondsTotal.value >= 86400);
|
|
const days = computed(() => Math.ceil(secondsTotal.value / 86400));
|
|
|
|
const hours = computed(() => {
|
|
const h = Math.floor(secondsTotal.value / 3600) % 24;
|
|
return h.toString().padStart(2, '0');
|
|
});
|
|
const minutes = computed(() => {
|
|
const m = Math.floor((secondsTotal.value % 3600) / 60);
|
|
return m.toString().padStart(2, '0');
|
|
});
|
|
const seconds = computed(() => {
|
|
const s = secondsTotal.value % 60;
|
|
return s.toString().padStart(2, '0');
|
|
});
|
|
|
|
const startTimer = () => {
|
|
timer = setInterval(() => {
|
|
now.value = Date.now();
|
|
}, props.interval);
|
|
};
|
|
|
|
const stopTimer = () => {
|
|
if (timer) {
|
|
clearInterval(timer);
|
|
timer = null;
|
|
}
|
|
};
|
|
|
|
onMounted(() => {
|
|
startTimer();
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
stopTimer();
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
.countdown-wrapper {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.time-block {
|
|
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
|
text-align: center;
|
|
font-weight: 500;
|
|
font-size: 28rpx;
|
|
color: #ffffff;
|
|
height: 44rpx;
|
|
line-height: 44rpx;
|
|
padding: 0 14rpx;
|
|
background: #256bfa;
|
|
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
|
margin: 0 10rpx;
|
|
}
|
|
|
|
.colon {
|
|
font-family: PingFang SC, PingFang SC;
|
|
font-weight: 400;
|
|
font-size: 28rpx;
|
|
color: #256bfa;
|
|
}
|
|
|
|
.day-text {
|
|
font-size: 18px;
|
|
color: #333;
|
|
}
|
|
|
|
.hui {
|
|
color: #b6b6b6;
|
|
}
|
|
.huibg {
|
|
background-color: #b6b6b6;
|
|
}
|
|
.lan {
|
|
color: #256bfa;
|
|
}
|
|
</style>
|