好久没有更新博客了。。。为了双十一准备了很多活动,终于结束了,有时间静静的坐下来总结一下了,在活动中最经常使用的就是倒计时了,晚上也有不少倒计时的例子了,那么今天带来的是一个新的方法和思路。android
既然要介绍新的方法那就要先说说如今已有的方法的特色了~相信不少刚刚出校门的孩子们还在用setinterval方法来作定时器吧,这种方法能够说是最简单和最明了的方法了,但是这样也带来了很明显的缺点,那就是setinterval方法在移动端上并不许确,并且及其消耗性能,在配置比较差的机型上还会卡死,因此为了流畅的倒计时,明显是不能使用这个方法的,因此,接下来我介绍今天的主角,请求动画帧(requestAnimationFrame)。ios
在博客园中也有不少介绍requestAnimationFrame的,在这里我就不赘述了,主要是在这个倒计时的时候采用到了这个方法,同时为了消除兼容性的问题,首先仍是要在代码中对requestAnimationFrame进行兼容性的设置的。代码以下:web
(function(window) { "use strict"; var lastTime = 0; window.requestAnimationFrame = window.requestAnimationFrame || window.webkitrequestAnimationFrame || function(callback) { var currTime = Date.now(), timeToCall = Math.max(0, 16 - (currTime - lastTime)), id = setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; })(window);
在设置已上代码以后即可以直接使用了,那么接下来就上倒计时的代码,而后我再一一介绍:服务器
/** * 小时级倒计时动画 * @param {String} time [服务器时间戳] * @param {String} time [倒计时截至时间] */ function _timeAnimation(time, timesNum) { var times = (timesNum - time), // 目标时间和服务器时间的差值 timeTemp, // 临时时间 remain_sec = 0, // 秒 remain_minute = 0, // 分钟 remain_hour = 0, // 小时 timetag = Date.now(), // 上一帧的时间 hour = 0, // 最终显示小时 min = 0, // 最终显示分钟 sec = 0, // 最终显示秒 doms = document.getElementById('times'); // 须要渲染的DOM元素 timeTemp = parseInt(times / 1000); // 秒数 remain_sec = timeTemp % 60; timeTemp = parseInt(timeTemp / 60); // 分数 remain_minute = timeTemp % 60; timeTemp = parseInt(timeTemp / 60); // 小时数 remain_hour = timeTemp % 24; timeTemp = parseInt(timeTemp / 24); function begin() { if ((Date.now() - timetag) >= 1000) { times = timesNum - Date.now(); timeTemp = parseInt(times / 1000); // 秒数 remain_sec = timeTemp % 60; timeTemp = parseInt(timeTemp / 60); // 分数 remain_minute = timeTemp % 60; timeTemp = parseInt(timeTemp / 60); // 小时数 remain_hour = timeTemp % 24; timeTemp = parseInt(timeTemp / 24); // 当时间结束后倒计时中止 if ((remain_minute <= 0) && (remain_sec <= 0) && (remain_hour <= 0)) { remain_minute = remain_sec = remain_hour = 0; return; } timetag = Date.now(); } // 如下部分作为时间显示时补零 if (remain_hour < 10) { hour = '0' + remain_hour; } else { hour = remain_hour; } if (remain_minute < 10) { min = '0' + remain_minute; } else { min = remain_minute; } if (remain_sec < 10) { sec = '0' + remain_sec; } else { sec = remain_sec; } doms.innerHTML = hour + ':' + min + ':' + sec; window.requestAnimationFrame(begin); } window.requestAnimationFrame(begin); }
如今代码贴上来了,那接下来我就介绍一下思路,正常来讲,不少人都会在初始化的时候计算出三个时间来,而后在分别在倒计时的时候减1,好比这样:dom
if ((Date.now() - timetag) >= 1000) { if (remain_sec > 0) { remain_sec--; } else if (remain_minute > 0) { remain_minute--; remain_sec = 59; } else if (remain_hour > 0) { remain_hour--; remain_minute = 60; } else { remain_hour = remain_minute = remain_sec = 0; return; } timetag = Date.now(); }
这样作的结果就是产生偏差,那么有同窗就要问了,这样会在什么状况下产生偏差呢?性能
那就是当用户触发了alert窗口的时候,js代码就会被阻塞,这个时候这样的倒计时就会中止,那么当用户再回来的时候就会产生必定的偏差,那有人问了,个人活动没有alert呢?会不会也产生偏差呢?或者说我不使用alert,而是用遮罩来模仿alert呢?这样会不会就能避免了呢?其实这样的话在android设备上还说的过去,可是在ios设备上面的话就会出问题,由于系统的特性,当用户点击屏幕以后,就会和alert同样阻塞代码的执行,因此这个时候若是用户不当心点了屏幕没有松手,那偏差就会不断的产生了。优化
因此就不能使用相似上面的倒计时方法了,为了不这样的偏差产生,因此应该是用当前时间减去上一帧的时间,而后转成秒去减,但这样其实也是有问题的,那就是若是用户阻塞的好久,十几分钟,几个小时的话就很差处理了,因此一个更加偷懒的办法就是用目标时间来减去当前时间,而后在去换算成小时,分钟和秒,就如同我代码上面的那样,而服务器的时间是否是就没有用了呢?并非,服务器的时间做为初始化的校验时间是十分有必要的,这样能够避免用户修改了本地时区的时候提早开始倒计时,因此须要服务器的时间来进行矫正,若是用户的时间比服务器的时间早,或者晚,那么就不进行倒计时了。动画
接下来就是喜闻乐见的补0操做了,由于上面的代码是最终精确到秒的,因此补0仍是很简单的,当你的精确度到达毫秒的时候就须要连续补2个0的时候了,这个时候我采用以下的方式来补偿:spa
var len = ms.toString().length; while (len < 3) { ms = "0" + ms; len++; }
又到了总结的时候了,首先使用了请求动画帧来避免了动画的卡顿,而后使用相对时间差的方式来避免阻塞产生的偏差,固然,上面的代码还有不少能够优化的地方,此次记录也是一次不彻底的总结吧,接下来我会再介绍一些平时工做用可能会注意到的地方,但愿能对刚刚走出校园的同窗一些帮助吧~加油~code
----jonnyf