web前端倒计时实现(解决前端倒计时误差问题)

/**
 * @param {date} expires - 过期时间
 * @param {date} sysTime - 系统时间,默认为客户端当前时间
 * @param {number} interval - 倒计时间隔,默认为1秒
 * @param {boolean} renturnDay - 返回时间是否包含天,默认false
 * @param {function} callback - 回调函数,回调数据格式如:{ d: 1, h: 1, m: 22, s: 58, ms: 4 },没回调数据时表示已结束。
 * @return {function} 用于暂停倒计时
 */
function startCountDown({ expires, sysTime = new Date(), interval = 1000, renturnDay = false, callback } = {}) {
	if (!expires) return;
	let timer = null;

	// 剩余时间
	let remainTime = new Date(expires).getTime() - new Date(sysTime).getTime();

	if (remainTime <= 0) {
		// 没回调入参说明已结束
		callback && callback();
		return;
	}

	let startTime = Date.now();

	function countDown() {
		let endTime = Date.now();
		// 这里不能直接用remainTime - interval,不然会有误差
		// 因为定时器不一定会完全按照interval间隔去执行,很多时候执行时,间隔都已经大于interval值了。
		remainTime = remainTime - (endTime - startTime);

		startTime = endTime;

		if (remainTime <= 0) {
			// 没回调入参说明已结束
			callback && callback();
		} else {
			callback && callback(getTimeData(remainTime, renturnDay));
			timer = setTimeout(countDown, interval);
		}
	}

	callback && callback(getTimeData(remainTime, renturnDay));
	timer = setTimeout(countDown, interval);

	return () => {
		timer && clearTimeout(timer);
		timer = null;
	}
}

function getTimeData(time = 0, renturnDay = false) {
	let d, h;
	if (renturnDay) {
		d = Math.floor((time / 1000 / 60 / 60 / 24));
		h = Math.floor((time / 1000 / 60 / 60 % 24));
	} else {
		h = Math.floor((time / 1000 / 60 / 60));
	}

	const m = Math.floor((time / 1000 / 60 % 60));
	const s = Math.floor((time / 1000 % 60));
	let ms = Math.floor(time % 1000);
	ms = parseInt(ms / 100);

    return { d, h, m, s, ms };
}


startCountDown({
    interval: 100,
    expires: new Date('2021-09-04 20:50'),
    renturnDay: true,
    callback: (data) => {
        if (data) {
            console.log(data.d, '天', data.h, '小时', data.m, '分', data.s, '秒', data.ms);
        } else {
        	console.log('倒计时结束');
        }
    }
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值