antd-mini
Version:
antd-mini 是支付宝小程序 UI 组件库,遵循 Ant Design 规范。
186 lines (164 loc) • 5.65 kB
text/typescript
import dayjs from 'dayjs';
import duration from 'dayjs/plugin/duration';
import {
Component,
getValueFromProps,
triggerEvent,
triggerEventOnly,
} from '../_util/simply';
import { CountdownDefaultProps } from './props';
dayjs.extend(duration);
Component({
props: CountdownDefaultProps,
data: {
countdownDay: null, // 注意这些倒计时相关的都应该是字符串
countdownHour: null, // 倒计时小时 注意都用字符串,避免0被判false的问题
countdownMin: null, // 倒计时分钟
countdownSec: null, // 倒计时秒
showDecisecond: true, // 倒计时结束时不展示秒后一位(厘秒)
},
methods: {
init() {
const [
countdownStartTime,
countdownEndTime,
countdownType,
time,
autoShowDay,
] = getValueFromProps(this, [
'countdownStartTime',
'countdownEndTime',
'countdownType',
'time',
'autoShowDay',
]);
const timeNum = isNaN(Number(time)) ? 0 : Number(time);
const defaultEndTime = +new Date() + timeNum * 1000;
const currentTimeStr = `${countdownStartTime || +new Date()}`;
const endTimeStr = `${countdownEndTime || defaultEndTime}`;
// 如果服务端给的是秒级别的时间戳,自动补3个0转成毫秒的
const finalCurrentTimeStr = `${currentTimeStr}${
currentTimeStr.length === 10 ? '000' : ''
}`;
const finalEndTimeStr = `${endTimeStr}${
endTimeStr.length === 10 ? '000' : ''
}`;
const finalStartTime = parseInt(finalCurrentTimeStr, 10);
const finalEndTime = parseInt(finalEndTimeStr, 10);
this.setData({
showDay: autoShowDay ? this.data.countdownDay !== '0' : true,
});
this.countdown(finalStartTime, finalEndTime, (remainTime) => {
if (remainTime < 1) {
// 小于1s了,说明倒计时该结束了
triggerEventOnly(this, 'countdownFinish');
this.setData({
showDecisecond: false,
});
}
const durationTime = dayjs.duration(remainTime);
const day = Math.floor(durationTime.asDays()).toString();
let hour = '';
if (countdownType === 'day') {
hour = durationTime.format('HH');
} else {
const hoursNum = Math.floor(durationTime.asHours());
hour = `${hoursNum < 10 ? '0' : ''}${hoursNum > 0 ? hoursNum : '0'}`;
}
const min = durationTime.format('mm');
const sec = durationTime.format('ss');
this.setData({
countdownDay: day,
countdownHour: hour,
countdownMin: min,
countdownSec: sec,
});
triggerEvent(this, 'countdownChange', {
remainTime,
day,
hour,
min,
sec,
});
});
},
countdown(
startTimestamp: number,
endTimestamp: number,
callback: (remainingTime: number) => void
) {
// if (isNaN(startTimestamp) || isNaN(endTimestamp)) {
// return;
// }
const currentTime = Date.now(); // 当前时间戳
if (
currentTime - Math.round(startTimestamp) < 10000 &&
Math.round(startTimestamp) - currentTime < 10000
) {
// 如果服务端下发的startTime时间戳和本机的时间戳相差10s以内,以本地时间戳为准
const getRemainingTime = (): number => {
// 本地时间戳与服务端时间戳差距在10s以内都属于正常的,可以直接用本地时间。
let remainingTime;
const newCurrentTime = +new Date();
// 判断是否到达结束时间
if (newCurrentTime >= endTimestamp) {
remainingTime = 0;
} else {
remainingTime = endTimestamp - newCurrentTime;
}
return remainingTime;
};
const updateCountdown = () => {
const remainingTime = getRemainingTime();
// 调用setData方法更新UI
callback(remainingTime);
if (remainingTime > 0) {
// 若还有剩余时间,延迟1秒后递归调用自身
this.timer = setTimeout(updateCountdown, 1000);
}
};
// 预先调一次
const remainingTime = getRemainingTime();
callback(remainingTime);
if (remainingTime === 0) {
// 如果第一次就是0,可以直接停了
return;
}
// 初始化倒计时
updateCountdown();
} else {
// 否则以服务端时间为准,直接算出当前剩余时间,按秒循环即可
const remainingTime = endTimestamp - startTimestamp;
const totalCount = Math.round(remainingTime / 1000);
let count = 0;
// 立刻调一次
callback(remainingTime - count * 1000);
// 每秒调一次,循环count次
this.intervalId = setInterval(() => {
if (count >= totalCount) {
clearInterval(this.intervalId);
} else {
count++;
// console.log('111111', remainingTime, count, remainingTime - count * 1000)
callback(remainingTime - count * 1000);
}
}, 1000);
}
},
},
onInit() {
this.init();
},
didUnmount() {
clearInterval(this.intervalId);
clearTimeout(this.timer);
},
didUpdate(prevProps) {
const autoShowDay = getValueFromProps(this, 'autoShowDay');
if (prevProps.autoShowDay !== autoShowDay) {
this.setData({
showDay: autoShowDay ? this.data.countdownDay !== '0' : true,
});
}
},
});