我的前端故事----疯狂倒计时(requestAnimationFrame)
很久没有更新博客了。。。为了双十一准备了不少活动,终于结束了,有时间静静的坐下来总结一下了,在活动中最常用的就是倒计时了,晚上也有很多倒计时的例子了,那么今天带来的是一个新的方法和思路。
既然要介绍新的方法那就要先说说现在已有的方法的特点了~相信很多刚刚出校门的孩子们还在用setinterval方法来做定时器吧,这种方法可以说是最简单和最明了的方法了,可是这样也带来了很明显的缺点,那就是setinterval方法在移动端上并不准确,而且及其消耗性能,在配置比较差的机型上还会卡死,所以为了流畅的倒计时,明显是不能使用这个方法的,所以,接下来我介绍今天的主角,请求动画帧(requestAnimationFrame)。
在博客园中也有很多介绍requestAnimationFrame的,在这里我就不赘述了,主要是在这个倒计时的时候采用到了这个方法,同时为了消除兼容性的问题,首先还是要在代码中对requestAnimationFrame进行兼容性的设置的。代码如下:
(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,比如这样:
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的时候了,这个时候我采用如下的方式来补偿:
var len = ms.toString().length;
while (len < 3) {
ms = "0" + ms;
len++;
}
又到了总结的时候了,首先使用了请求动画帧来避免了动画的卡顿,然后使用相对时间差的方式来避免阻塞产生的误差,当然,上面的代码还有很多可以优化的地方,这次记录也是一次不完全的总结吧,接下来我会再介绍一些平时工作用可能会注意到的地方,希望能对刚刚走出校园的同学一些帮助吧~加油~
----jonnyf
我的前端故事----疯狂倒计时(requestAnimationFrame)的更多相关文章
- 我的前端故事----我为什么用GraphQL
背景 今年我在做一个有关商户的app,这是一个包含商户从入网到审核.从驳回提交到入网维护的完整的生命周期线下推广人员使用的客户端软件,但故事并没有这么简单... 疑问 随着app的逐渐完善,遇到的问题 ...
- 我的前端故事----优美的编辑器GitHub Atom
很多前端的同学都在用sublime text,我之前也在使用,但是后来接触到了Atom,就被它的高颜值深深的吸引了~~不愧是GitHub的工程师哦~审美就是高 Atom 作为一个跨平台的编辑软件,安 ...
- 我的前端故事----Ajax方式和jsonp的实现区别
很久没有更新博客了,毕业2个月了,这段时间一直在忙于工作,一直没有时间更新,最近做的活动突然发现之前的经验居然忘记了...索性想想还是重新开始用博客记录平日里的工作经验吧,吐槽就到这里了,这篇记录的是 ...
- 我的前端故事----关于redux的一些思考
背景 我一个前端,今年第一份工作就是接手一个 APP 的开发...一个线下 BD 人员用的推广 APP,为了让我这个一天原生开发都没有学过的人能快速开发上线,于是乎就选择了 react-native ...
- 我的前端故事----关于前端数据&逻辑的思考
最近重构了一个项目,一个基于redux模型的react-native项目,目标是在混乱的代码中梳理出一个清晰的结构来,为了实现这个目标,首先需要对项目的结构做分层处理,将各个逻辑分离出来,这里我是基于 ...
- 我的前端故事----来聊聊怎么写react-native上的样式吧
我遇到了什么问题? 不久之前我重构了一个古老的项目,总结了一些js方面的想法,不过对于一个前端项目而言不仅仅只由js组成的嘛,上学的时候老师和我说HTML+CSS+JS对应的是页面的骨架.皮肤和肌肉. ...
- 我的前端故事----来聊聊react-native应用的健康监控
监控什么 今天我们来聊聊如何监控你的应用程序,这里的监控说的不是让我们去监控用户,而是监控应用的健康状态,什么是健康状态呢?对于后端的同学来说,在微服务的架构下,每个子服务是否正常工作.返回的结果是否 ...
- 与JavaWeb有关的故事(web请求与Java I/O)
作为一名后端屌丝程序员,对算法.并发.性能乐此不疲.但是,随着年龄和阅历的增加,显然叶落而不知秋的心态是不太能混了.尤其是,某T面试官在明知我是后端,且明确表示对HTTP协议不太熟的情况下,强行让我解 ...
- 与JavaWeb有关的故事(Web请求与Java IO)
作为一名后端屌丝程序员,对算法.并发.性能乐此不疲.但是,随着年龄和阅历的增加,显然叶落而不知秋的心态是不太能混了.尤其是,某T面试官在明知我是后端,且明确表示对HTTP协议不太熟的情况下,强行让我解 ...
随机推荐
- JavaScript学习笔记(1))——————call,apply方法
学习前端也有一段时间了,但是效果甚微.利用时间不够充分,虽然是利用工作之余来学习.但是这不能成为我的借口. 今天学习了(其实看了很多遍)call apply方法. function abc(a,b){ ...
- springmvc拦截器验证登录时间
在前一篇[Filter实现用户名验证]的随笔里,记录了如何使用filter 这次增加了拦截器实现 ①filter实现用户登陆时验证用户名是否为null ②interceptor实现用户登陆时时间判断, ...
- kali python pip3 的安装和卸载
今天很高兴安装完成调整了kali 然后看见kali已经帮助我安装了python2.7和python3.5可把我开心坏了,可是2.7有pip,而且包很全,但2.7与3.0切换使用我的就尴尬了 最后在su ...
- Solr使用入门指南
本文转自http://chuanliang2007.spaces.live.com/blog/cns!E5B7AB2851A4C9D2!499.entry?wa=wsignin1.0 由于搜索引擎功能 ...
- 页面无刷新Upload File
页面无刷新Upload File. 利用jquery.form.js的ajaxForm提交文件. 具体参考以下代码: 前台html <%@ Page Language="C#" ...
- SWFUpload多图上传、C#后端跨域传文件带参数
前几天工作中用到了SWFUpload上传图片,涉及到跨域,因为前端无法实现跨域,所以只能把文件传到后端进行跨域请求,整理分享下. 效果图 前端 html部分 <!DOCTYPE html> ...
- iOS 私有变量 私有方法
实例变量既可以在@interface中定义 也可以在@implementation中定义 在@implementation中的成员变量默认是私有的成员变量 并且和利用@private修饰的不太一样 在 ...
- .net项目中上传的图片或者文件太大 无法上传
最近做项目的时候 用户提出要上传大图片 一张图片有可能十几兆 本来用的第三方的上传控件 有限制图片上传大小的设置 以前设置的是2M 按照用户的要求 以为直接将限制图片上传大小的设置改下就可 ...
- 读取Simulink中Dataset类型的数据
http://files.cnblogs.com/files/pursuiting/%E5%80%92%E7%AB%8B%E6%91%86%E6%8E%A7%E5%88%B6%E7%B3%BB%E7% ...
- 模拟搭建Web项目的真实运行环境(五)
一.开启IIS功能 刚安装完的server2008是没有默认开启IIS功能,在这里简单介绍一下如何开启IIS. 步骤: 1. 打开控制面板,选中[程序] 2. 在[程序和功能]下面,选择[打开或关闭w ...