之前做的电商项目,前端项目是用VUE开发的,基于VUE实现了倒计时组件。最近有个项目是REACT开发的,也需要用到倒计时组件,由于使用的是不同的框架,组件无法复用,所以特意提供一个实现了倒计时功能的函数,方便在此函数的基础上封装组件, 也在此做下记录, 方便下次查阅。直接上代码:
const checkParams = (startDate, endDate, format) => {
if (!startDate) {
throw new Error('startDate is not be null');
}
// 开始日期数据类型
const startType = Object.prototype.toString.call(startDate).slice(8, -1);
const allowType = ['String', 'Date'];
if (!allowType.includes(startType)) {
throw new Error('startDate type is error, allow String or Date');
}
// 开始日期数据类型
const endType = Object.prototype.toString.call(endDate).slice(8, -1);
if (!allowType.includes(endType)) {
throw new Error('endDate is error, allow String or Date');
}
};
const stringToDate = (date) =>{
if (typeof date === 'string') {
// 日期字符串转换为日期对象,并兼容ios
return new Date(Date.parse(date.replace(/-/g, '/')));
}
};
/**
* 单个数字格式化为两位数, 9 => 09
* @param num
* @returns {string}
*/
const formatTwoDigit = (num) => {
if (num < 10) {
return (Array(2).join('0') + num).slice(-2);
}
return num;
};
/**
* 倒计时
* @param params - 参数, 包含以下属性:
* startDate - 开始时间, 默认当前日期, 支持日期格式的字符串以及date对象
* endDate - 结束时间, 支持日期格式的字符串以及date对象
* format - 格式化, 默认hh:mm:ss, dd - 天, hh - 时, mm - 分, ss - 秒
* cb(isEnd, result, hh, mm, ss) - 回调函数, isEnd - 是否结束, result - 根据format格式化后的结果, 后续参数是根据format返回相应的数值
*/
const countDown = (params = {}) => {
let { startDate, endDate = new Date(), format = 'hh:mm:ss', cb = () => {} } = params;
checkParams(startDate, endDate, format);
let interval = null;
startDate = stringToDate(startDate);
endDate = stringToDate(endDate);
const startTime = startDate.getTime(), endTime = endDate.getTime();
if (isNaN(startTime)) {
throw new Error('startDate not in date format');
}
if (isNaN(endTime)) {
throw new Error('end not in date format');
}
// 获取相差的毫秒数
let diffTime = endTime - startTime;
if (diffTime > 0) {
interval = setInterval(() => {
if (diffTime <= 0) {
clearInterval(interval);
interval = null;
}
let m = formatTwoDigit(Math.floor(diffTime/1000/60%60));
let s = formatTwoDigit(Math.floor(diffTime/1000%60));
let result = '';
// dd:hh:mm:ss
if(/^(d{2}).+(h{2}).+(m{2}).+(s{2})$/.test(format)){
let d = formatTwoDigit(Math.floor(diffTime/1000/60/60/24));
let h = formatTwoDigit(Math.floor(diffTime/1000/60/60%24));
result = format
.replace(/dd/, d)
.replace(/hh/, h)
.replace(/mm/, m)
.replace(/ss/, s);
cb(diffTime <= 0, result, d, h, m, s);
}
// hh:mm:ss
else if (/^(h{2}).+(m{2}).+(s{2})$/.test(format)) {
let h = formatTwoDigit(Math.floor(diffTime/1000/60/60));
result = format
.replace(/hh/, h)
.replace(/mm/, m)
.replace(/ss/, s);
cb(diffTime <= 0, result, h, m, s);
}
// mm:ss
else if (/^(m{2}).+(s{2})$/.test(format)) {
console.log(diffTime);
m = formatTwoDigit(Math.floor(diffTime/1000/60));
result = format
.replace(/mm/, m)
.replace(/ss/, s);
cb(diffTime <= 0, result, m, s);
} else {
clearInterval(interval);
interval = null;
throw new Error('format is error');
}
diffTime -= 1000;
}, 1000);
}
};
测试代码:
countDown({
startDate: '2020-09-21 17:59:50',
endDate: '2020-09-21 18:00:00',
cb: (isEnd, result) =>{
console.log(isEnd, result);
}
});