automated_uniapp/uni_modules/cool-ui/components/cl-countdown/cl-countdown.vue
2025-01-09 16:16:11 +08:00

274 lines
4.5 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="cl-countdown"
:style="{
'font-size': parseRpx(fontSize),
}"
v-if="visible"
>
<template v-for="(item, index) in list" :key="index">
<view class="cl-countdown__item" :style="item.ch ? textStyle : numberStyle">
{{ item.value }}
</view>
</template>
</view>
</template>
<script lang="ts">
import { defineComponent, ref, watch, nextTick, onBeforeUnmount, onBeforeMount } from "vue";
import { parseRpx } from "/@/cool/utils";
export default defineComponent({
name: "cl-countdown",
props: {
// 格式化
format: {
type: String,
default: "{h}:{m}:{s}",
},
// 是否精简为00时自动隐藏
simple: {
type: Boolean,
default: false,
},
// 还有多少天
day: {
type: Number,
default: 0,
},
// 还有多少小时
hour: {
type: Number,
default: 0,
},
// 还有多少分钟
minute: {
type: Number,
default: 0,
},
// 还有多少秒
second: {
type: Number,
default: 0,
},
// 结束时间
datetime: [Date, String],
// 数字样式
numberStyle: Object,
// 分隔符样式
textStyle: Object,
// 字体大小
fontSize: {
type: Number,
default: 26,
},
},
emits: ["stop", "done", "change"],
setup(props, { emit }) {
let timer: any = null;
// 秒
const seconds = ref(0);
// 状态
let status = false;
// 是否显示
const visible = ref(true);
// 列表
const list = ref<any[]>([]);
// 转成秒
function toSeconds({ day = 0, hour = 0, minute = 0, second = 0, datetime }: any) {
if (datetime) {
return (
(new Date(datetime.replace(/-/g, "/")).getTime() - new Date().getTime()) / 1000
);
} else {
return day * 60 * 60 * 24 + hour * 60 * 60 + minute * 60 + second;
}
}
// 开始倒计时
function start(options?: any) {
visible.value = true;
nextTick(() => {
let { day, hour, minute, second, datetime } = options || {};
if (!day) {
day = props.day;
}
if (!hour) {
hour = props.hour;
}
if (!minute) {
minute = props.minute;
}
if (!second) {
second = props.second;
}
if (!datetime) {
datetime = props.datetime;
}
seconds.value = toSeconds({
day,
hour,
minute,
second,
datetime,
});
next();
});
}
// 继续倒计时
function next() {
if (seconds.value <= 0) {
return;
}
if (status) {
return;
}
status = true;
// 开始
function next() {
countDown();
if (seconds.value <= 0) {
done();
return;
} else {
seconds.value--;
timer = setTimeout(next, 1000);
}
}
next();
}
// 停止
function stop() {
clear();
emit("stop");
}
// 结束
function done() {
visible.value = false;
clear();
emit("done");
}
// 清除定时器
function clear() {
clearTimeout(timer);
timer = null;
status = false;
}
// 倒计时执行
function countDown() {
let [day, hour, minute, second]: any = [0, 0, 0, 0];
day = Math.floor(seconds.value / (60 * 60 * 24));
hour = Math.floor(seconds.value / (60 * 60)) - day * 24;
minute = Math.floor(seconds.value / 60) - day * 24 * 60 - hour * 60;
second = Math.floor(seconds.value) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60;
if (day < 10) {
day = "0" + day;
}
if (hour < 10) {
hour = "0" + hour;
}
if (minute < 10) {
minute = "0" + minute;
}
if (second < 10) {
second = "0" + second;
}
const d: any = {
d: day,
h: hour,
m: minute,
s: second,
};
let arr: any[] = props.format
.split(/[{,}]/)
.filter(Boolean)
.map((e) => {
return {
value: d[e] ? d[e] : e,
ch: d[e] === undefined,
};
});
let f = true;
let n = -1;
list.value = arr
.map((e, i) => {
if (props.simple) {
if (!e.ch) {
if (f) {
if (e.value == "00") {
n = i;
f = true;
} else {
f = false;
}
}
}
}
return e;
})
.filter((_, i) => {
return n == -1 ? true : n + 1 < i;
});
emit(
"change",
list.value.map((e) => e.value),
);
}
onBeforeUnmount(clear);
onBeforeMount(start);
watch(() => props.day, start);
watch(() => props.hour, start);
watch(() => props.minute, start);
watch(() => props.second, start);
watch(() => props.datetime, start);
return {
visible,
seconds,
list,
start,
stop,
toSeconds,
parseRpx,
};
},
});
</script>