关于倒计时:如何在页面中实现倒计时功能

moment计算两个工夫差值moment(endTime).diff(moment(startTime), 'years')moment(endTime).diff(moment(startTime), 'months')moment(endTime).diff(moment(startTime), 'days')    //  开始工夫和完结工夫的时间差,以“天”为单位;endTime和startTime都是毫秒数moment(endTime).diff(moment(startTime),'minutes' )moment(endTime).diff(moment(startTime), 'seconds')原生实现用立刻执行函数封装一个倒计时插件,外头用moment插件中的diff办法计算两个时间段的差值,并以想要的模式返回,默认以毫秒差模式返回 //定义一个立刻执行的函数(function () { var Ticts=function Ticts() { this.ticts = {}; }; Ticts.prototype.createTicts=function(id, dealline) { var ticts=this; var time=moment(dealline).diff(moment()); var _ticts=this.ticts[id] = { dealine: dealline , id: id , time: time , interval: setInterval(function () { var t = null; var d = null; var h = null; var m = null; var s = null; //js默认工夫戳为毫秒,须要转化成秒 t = _ticts.time / 1000; d = Math.floor(t / (24 * 3600)); h = Math.floor((t - 24 * 3600 * d) / 3600); m = Math.floor((t - 24 * 3600 * d - h * 3600) / 60); s = Math.floor((t - 24 * 3600 * d - h * 3600 - m * 60)); //这里能够做一个格式化的解决,甚至做毫秒级的页面渲染,基于DOM操作,太多个倒计时一起会导致页面性能降落 document.getElementById(id).innerHTML = d + '天' + h + '小时' + m + '分钟' + s + '秒'; _ticts.time -= 1000; if (_ticts.time < 0) ticts.deleteTicts(id);//判断是否到期,到期后主动删除定时器 }, 1000) } }; Ticts.prototype.deleteTicts = function(id) { clearInterval(this.ticts[id].interval);//分明定时器的办法,须要定时器的指针作为参数传入clearInterval delete this.ticts[id];//通过delete的办法删除对象中的属性 }; //新建一个ticts对象,放到window全局函数中,那么在html页面是(或者其余js文件)能够拜访该对象 window.Ticts=new Ticts();})();React实现import React from 'react';import moment from 'moment';interface props { deadline: number; // 截止工夫戳}const CountDown = (props: IProps) => { const { deadline } = props; const [time, setTime] = useState(Date.now()); useEffect(() => { let timer: NodeJS.Timeout | null = null; if (deadline && deadline > time) { timer = setInterval(() => { if (deadline - time < 1000 && timer) { if (timer) clearInterval(timer); } setTime(Date.now()); }, 1000); } return () => { if (timer) clearInterval(timer); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [deadline]); const format = () => { const t = moment(deadline).diff(moment(time), 'seconds'); const d = Math.floor(t / (24 * 3600)); const h = Math.floor((t - 24 * 3600 * d) / 3600); const m = Math.floor((t - 24 * 3600 * d - h * 3600) / 60); const s = Math.floor(t - 24 * 3600 * d - h * 3600 - m * 60); return [d * 24 + h, m, s]; }; const countDown = format(); return ( <span>还剩{countDown[0]}小时{countDown[1]}分钟{countDown[2]}秒</span> )}

May 13, 2021 · 2 min · jiezi

活动倒计时实践与思考

聊一下活动倒计时的一些实践方案与思考。方案总体来说分为两种:方案一:依赖本地时间当然不能简单粗暴的直接获取本地时间来倒计时,结果可能是每个用户的倒计时时间千差万别,而且用户可以恶意更改本地时间去绕过倒计时操作。 方案:接口获取到服务前当前时间以后,与本地时间做一个差值计算。循环中使用本地时间加时间差得出当前时间,来计算倒计时时间,并在一定频率内更新服务器、本地时间差值。// 接口获取服务器当前时间,并计算与本地时间的时间差const timeDiff = serverTime - new Date().getTime()setTimeout(() => { // 当前时间 = 本地时间 + 时间差 const currTime = new Date().getTime() + timeDiff // 倒计时时间 = 截止时间 - 当前时间 const countDown = endTime - currTime // 显示倒计时信息 setCountDownInfo(countDown)}, 1000)优点:js倒计时有延迟。如果单纯使用js的setTimeout倒计时,代码运行时间越长偏差越大,本地时间的准确性就很可以实时纠正js倒计时的偏差。pc端浏览器进入后台运行,js计时器会变慢;移动端应用进入后台运行,js计时器会直接停止,导致倒计时严重偏差。而依赖本地时间,就可以纠正这些偏差。缺点:用户也是可以修改本地时间绕过计时器的。需要一定的频率,获取服务器时间更新时间差值,防止用户修改本地时间。 方案二:js倒计时方案:获取到服务器时间以后,js用setTimeout做倒计时,不依赖本地时间。// 接口获取服务器当前时间let currTime = serverTimesetTimeout(() => { // 当前时间 = 服务器时间 循环累加 currTime = currTime + 1000 // 倒计时时间 = 截止时间 - 当前时间 const countDown = endTime - currTime // 显示倒计时信息 setCountDownInfo(countDown)}, 1000)优点:解决了依赖本地时间的弊端缺点:前边提过,js定时器有偏差;页面后台运行,定时器会变慢。需要一定的频率,获取服务器当前时间矫正这些偏差思考一:校准时间的频率无论上述哪种方案,无论矫正js定时器偏差还是更新时间差值防止修改本地时间,频率的设定都很重要,可以根据场景区分 ...

November 5, 2019 · 1 min · jiezi

小程序倒计时深究

小程序倒计时重叠抖动问题因为请求数据写在onShow 函数里面,所以每次切换界面都会刷新,这就会导致,如果当前 定时器在跑的话,再次刷新会再次常见定时, 那么就会导致刷新几次有几个定时器,同时在跑,那么前端界面显示的计时数字 就会不时跳动,所以需要保证在跑的定时器只有一个。将定时器对象创建为全局的,在每次开启定时器的时候先清空之前的定时器。就可以解决刷新后计时闪动的问题了,或者在在tab页面,运用 onHide 周期 进行 clearTimeInterval清空 , 在 非tab页面,运用onUload() 周期 进行 clearTimeInterval清空,百度都可以找到类似解决方案,其中在我的历史文章小程序实战踩坑之B2B商城项目总结也有总结,代码类似如下:/** * 清除interval * @param that / clearTimeInterval: function (that) { var interval = that.data.interval; clearInterval(interval) }, /* * 生命周期函数–监听页面卸载 * 退出本页面时停止计时器 / onUnload:function () { var that = this; that.clearTimeInterval(that) }, /* * 生命周期函数–监听页面隐藏 * 在后台运行时停止计时器 */ onHide:function () { var that = this; that.clearTimeInterval(that) }倒计时使用setInterval或setTimeout触摸屏幕导致时间显示的突跳,突慢问题,卡顿,甚至停止不信的同学,可以尝试用手指触摸屏幕,上下小幅上下移动不放,你会发觉时间竟然停止了。(特别是针对低端机型)通常同学写代码都会如此: let self = this; let lefttimeSec = time - new Date().getTime(); let calc = setInterval(function() { lefttimeSec -= 1000; self.endtimestr = ‘距离拼单结束还有’ + self.dateformat(lefttimeSec); self.$apply(); if (lefttimeSec <= 0) { clearInterval(calc); } }, 1000);使用setInterval后,即使用了上面说的“小程序倒计时重叠抖动问题”解决方案,只是解决了倒计时重叠问题,这样写法,会导致的一些精准度不高。其实很简单,解决代码如下: showCountTime(time){ let self = this; setTimeout(function(){ let lefttimeSec = time - new Date().getTime(); lefttimeSec -= 1000; self.endtimestr = ‘距离拼单结束还有’ + self.dateformat(lefttimeSec); self.$apply(); self.showCountTime(time); },1000); }注意,这里用了setTimeout,要tab页面,运用onHide周期进行clearTimeout清空, 在非tab页面,运用onUload()周期 进行clearTimeout清空定时器。这步必须要做,就不多说了,要不还是会出现上面说的“小程序倒计时重叠抖动问题”问题。用了上面代码,补失的精准度不足。小心的测试同学会发现触摸屏幕导致的突跳,突慢问题,甚至停止!于是各种寻思,去找了拼多多小程序,京东购物小程序各种对比。 结论是拼多多存在和我一样的问题,京东购物小程序的倒计时没这样的问题,给个赞!出现问题环境描述:小程序框架:wepy : “^1.7.2"测试机型:红米3自身思路是wepy脏检查在触摸(滚动)屏幕下引起性能占用导致的一些效率不足问题,做了进一步测试,还是用红米3机型,抛掉组件,抛掉data,只保留data,做一个简单的渲染,将页面高度固定,让屏幕可以上下滑动,代码如下:<style> .content { height: 2000rpx; border: 1rpx solid red; } .child { height: 500rpx; }</style><template> <view class=“content”> <view class=“child”></view> {{endtimestr}} </view></template><script> import wepy from ‘wepy’; export default class test extends wepy.page { data = { endtimestr: ’’ } showCountTime(time) { let self = this; setTimeout(function() { let lefttimeSec = time - new Date().getTime(); lefttimeSec -= 1000; self.endtimestr = ‘距离拼单结束还有’ + self.dateformat(lefttimeSec); self.$apply(); self.showCountTime(time); }, 1000); } dateformat = (micro_second) => { // 总秒数 var second = Math.floor(micro_second / 1000); // 天数 var day = Math.floor(second / 3600 / 24); // 小时 var hr = Math.floor(second / 3600 % 24); // 分钟 var min = Math.floor(second / 60 % 60); // 秒 var sec = Math.floor(second % 60); hr = hr < 10 ? ‘0’ + hr : hr; min = min < 10 ? ‘0’ + min : min; sec = sec < 10 ? ‘0’ + sec : sec; if (day > 0) { return day + " 天” + ’ ’ + hr + “:” + min + “:” + sec; } else { return hr + “:” + min + “:” + sec; } } onLoad() { //api模拟得到time this.showCountTime(1545899950167); } }</script>结论是: 倒计时在触摸(滚动)情况下正常了!!!那也表明wepy的脏检查存在一些性能的不足呀,希望未来wepy有改进! ...

December 27, 2018 · 2 min · jiezi