JS 代码编一个倒时器
有时候在生活中,你需要一个JavaScript倒计时时钟,而不是一个末日装置设备。不管你是否有一次约会,销售、促销、或者游戏,你可以受益于使用原生JavaScript构建一个时钟,而不是拿到一个现成的插件。虽然有许多很棒的时钟插件,但如果使用原生 JavaScript 实现,那你将得到以下好处:
代码将是轻量级的,因为它没有依赖关系。
你的网站会表现得更好,因为你不需要加载外部脚本和样式表。
你将会有更高的可控性,因为你将按照想要的时钟行为的方式来创建它(而不是找一个趋向你想法的插件)。
所以事不宜迟,以下是如何使用仅仅18行JavaScript代码来做一个自己的倒计时时钟。
基础时钟:倒计时到特定的日期或时间
以下是创建一个基础时钟的快速概要步骤:
设置一个有效的结束日期。
计算剩余时间。
将时间转换成可用的格式。
输出时钟数据作为一个可重用的对象。
在页面上显示时钟,并在它到达0时停止。
设置一个有效的结束日期
首先,你需要设置一个有效的结束日期。它是JavaScript Date.parse()方法能够解析的任何格式的一个字符串。例如:
ISO 8601格式:
var deadline = '2015-12-31';
短格式:
var deadline = '31/12/2015';
或者,长格式:
var deadline = 'December 31 2015';
这些格式都可以指定一个确切的时间(小时,分钟和秒),以及时区(或者如果是ISO日期,则是UTC的偏移量)。例如:
var deadline = 'December 31 2015 23:59:59 GMT+02:00';
你可以在 此文阅读更多关于JavaScript的日期格式化。
计算剩余时间
下一步是计算剩余时间。做到这一点,我们需要编写一个函数,它接收一个代表给定结束时间的字符串(如上所述),并计算这个时间和当前时间的差值。代码如下:
function getTimeRemaining(endtime){
var t = Date.parse(endtime) - Date.parse(new Date());
var seconds = Math.floor( (t/1000) % 60 );
var minutes = Math.floor( (t/1000/60) % 60 );
var hours = Math.floor( (t/(1000*60*60)) % 24 );
var days = Math.floor( t/(1000*60*60*24) );
return {
'total': t,
'days': days,
'hours': hours,
'minutes': minutes,
'seconds': seconds
};
}
首先,我们创建一个变量t,保存剩下的时间期限。Date.parse()函数是原生JavaScript,它将一个时间字符串转换成以毫秒为单位的值。这让我们可以将两个时间相减,并获得间隔时间。
var t = Date.parse(endtime) - Date.parse(new Date());
转换时间为可用的格式
现在我们想把毫秒转换成天、小时、分钟、秒。让我们以秒为例:
var seconds = Math.floor( (t/1000) % 60 );
让我们解释这是怎么回事。
毫秒除以1000转换为秒:(t / 1000)
总秒除以60,获取余数——你不想要所有的秒,只是(t / 1000)%60之后的分钟剩余的秒数
将它取整,因为你想要完整的秒,而不是分数秒:Math.floor((t / 1000)% 60)
重复这个逻辑将秒转换为分钟、小时、天。
输出时钟数据作为一个可重用的对象
准备好天、小时、分钟和秒,我们现在准备将数据作为一个可重用的对象返回:
return {
'total': t,
'days': days,
'hours': hours,
'minutes': minutes,
'seconds': seconds
};
该对象允许你调用函数,得到任何已计算的值。这里有一个如何得到剩余分钟的例子:
getTimeRemaining(deadline).minutes
很方便,对吗?
在页面上显示时钟,并在它到达0时停止。
现在,我们有一个函数,它可以提取天、小时、分钟和秒,我们可以构建时钟了。首先,我们将创建以下HTML元素来存放我们的时钟:
<div id="clockdiv"></div>
然后我们将编写一个函数,输出时钟数据到新div:
function initializeClock(id, endtime){
var clock = document.getElementById(id);
var timeinterval = setInterval(function(){
var t = getTimeRemaining(endtime);
clock.innerHTML = 'days: ' + t.days + '<br>' +
'hours: '+ t.hours + '<br>' +
'minutes: ' + t.minutes + '<br>' +
'seconds: ' + t.seconds;
if(t.total<=0){
clearInterval(timeinterval);
}
},1000);
}
这个函数接收两个参数:显示时钟的元素的id和倒计时的结束时间。在函数内部,我们将声明一个名为clock的变量用来保存时钟容器div的引用,这样我们不需要不断查询DOM。
接下来,我们将使用setInterval每秒钟执行一次匿名函数,它将执行以下操作:
计算剩余时间。
将剩余时间输出到div。
如果剩余时间到达0,停止时钟。
到这里,唯一剩下的步骤运行时钟如下:
initializeClock('clockdiv', deadline);
恭喜你!你现在有一个基本的时钟,它只有短短18行JavaScript代码。
优化时钟显示
给时钟加样式之前,我们需要完善一点的东西。
移除初始加载的延迟,这样时钟会立即出现。
为了让时钟脚本更有效率,不要不断重建整个时钟。
根据需要添加前缀0。
移除初始加载的延迟
在时钟中,我们用setInterval每秒钟更新显示。大部分时间都很好,除了一开始的时候会有一秒钟的延迟。为了消除这个延迟,我们将不得不在间隔开始前就更新时钟。
要做到这一点,将传递给setInterval(它每秒钟更新时钟)的匿名函数迁移到一个独立的函数,命名为updateClock。在setInterval外调用updateClock一次,然后在setInterval里面再次调用,这种方式,时钟显示的时候就没有延迟。
在你的JavaScript中,替换:
var timeinterval = setInterval(function(){ ... },1000);
为
function updateClock(){
var t = getTimeRemaining(endtime);
clock.innerHTML = 'days: ' + t.days + '<br>' +
'hours: '+ t.hours + '<br>' +
'minutes: ' + t.minutes + '<br>' +
'seconds: ' + t.seconds;
if(t.total>=0){
clearInterval(timeinterval);
}
}
updateClock(); // run function once at first to avoid delay
var timeinterval = setInterval(updateClock,1000);
避免不断重建时钟
让时钟脚本更有效率,我们希望只更新时钟的数据,而不是每一秒重建整个时钟。实现这一目标的方法是,把每个数字嵌入到span标签内,只更新这些span的内容。
HTML:
<div id="clockdiv">
Days: <span class="days"></span><br>
Hours: <span class="hours"></span><br>
Minutes: <span class="minutes"></span><br>
Seconds: <span class="seconds"></span>
</div>
现在获取这些元素的引用。在clock变量定义的下面添加以下代码
var daysSpan = clock.querySelector('.days');
var hoursSpan = clock.querySelector('.hours');
var minutesSpan = clock.querySelector('.minutes');
var secondsSpan = clock.querySelector('.seconds');
接下来,我们只需要改变updateClock函数来更新数据而不是重建整个时钟。新代码是这样的:
function updateClock(){
var t = getTimeRemaining(endtime);
daysSpan.innerHTML = t.days;
hoursSpan.innerHTML = t.hours;
minutesSpan.innerHTML = t.minutes;
secondsSpan.innerHTML = t.seconds;
...
}
添加前导零
现在时钟更新数据,而不是每一秒重建,我们还有一件事要做:添加前导零。例如,时钟显示7秒时,让它显示07。一个简单的方法是在数字的开始处添加一个字符串“0”,然后获取最后两位数。
例如,为“seconds”添加一个前导零,你会这样改变:
secondsSpan.innerHTML = t.seconds;
变成:
secondsSpan.innerHTML = ('0' + t.seconds).slice(-2);
如果你愿意,你可以为minutes和hours添加前导零。如果你已经走了这么远,那么恭喜你!你的时钟可以显示了。
注意:您可能需要点击CodePen中的“Rerun”来启动倒计时。
更进一步
下面的例子演示了如何为某些场景设计时钟。他们都是基于上面的基础例子。
自动安排时钟
假设我们希望时钟出现在特定的某些天。例如,我们可能会有一系列的事件出现,同时不想每次都手动更新时钟。下面介绍如何提前进行规划安排。
在CSS中通过设置display属性为none来隐藏时钟。然后添加以下代码到initializeClock函数(在var clock语句的后面)。这将导致时钟只在initializeClock函数被调用显示:
clock.style.display = 'block';
接下来,我们可以指定时钟应该出现的时间段。这将替换deadline变量:
var schedule = [
['Jul 25 2015', 'Sept 20 2015'],
['Sept 21 2015', 'Jul 25 2016'],
['Jul 25 2016', 'Jul 25 2030']
];
schedule数组中的每个元素代表了一个开始日期和结束日期。如上所述,可以包括时间和时区,但这里我用纯日期来保持代码的可读性。
最后,当用户加载页面时,我们需要检查,是否在指定的时间段内。这段代码应该替换之前调用initializeClock函数的部分。
// iterate over each element in the schedule
for(var i=0; i&lt;schedule.length; i++){
var startDate = schedule[i][0];
var endDate = schedule[i][1];
// put dates in milliseconds for easy comparisons
var startMs = Date.parse(startDate);
var endMs = Date.parse(endDate);
var currentMs = Date.parse(new Date());
// if current date is between start and end dates, display clock
if(endMs &gt; currentMs &amp;&amp; currentMs &gt;= startMs ){
initializeClock('clockdiv', endDate);
}
}
现在你可以提前安排你的时钟,而不必手动更新它。你可以简化代码。我为了可读性写的有点详细。
当用户到达倒计时
有时有必要为一个用户到达或开始一个特别任务的给定时间设置一个倒计时。这里我们将使用十分钟,但是您可以使用任何你想要的时间。
所有我们需要做的是将deadline变量替换为:
var timeInMinutes = 10;
var currentTime = Date.parse(new Date());
var deadline = new Date(currentTime + timeInMinutes*60*1000);
这段代码将当前时间增加了十分钟。再转换为毫秒,所以他们可以相加在一起,并转换成一个新的截止日期。
现在我们有一个时钟,在十分钟用户到达时倒计时。请随便玩,尝试不同的时间长度。
跨页面保持时钟
有时有必要不仅仅为当前页面保持时钟的状态。例如,如果我们希望整个网站有一个十分钟的倒计时,我们不希望每次用户进入不同的页面或每次用户刷新页面时重置时钟。
一个解决方案是将时钟的结束时间保存在cookie。这样,导航到一个新的页面不会重置结束时间为十分钟。
逻辑是这样的:
如果deadline记录在一个cookie中,使用deadline。
如果cookie不存在,创建一个新的deadline并将它存储在一个cookie中。
为了实现这一点,如下替换deadline变量:
// if there's a cookie with the name myClock, use that value as the deadline
if(document.cookie &amp;&amp; document.cookie.match('myClock')){
// get deadline value from cookie
var deadline = document.cookie.match(/(^|;)myClock=([^;]+)/)[2];
}
// otherwise, set a deadline 10 minutes from now and
// save it in a cookie with that name
else{
// create deadline 10 minutes from now
var timeInMinutes = 10;
var currentTime = Date.parse(new Date());
var deadline = new Date(currentTime + timeInMinutes*60*1000);
// store deadline in cookie for future reference
document.cookie = 'myClock=' + deadline + '; path=/; domain=.yourdomain.com';
}
这段代码使用了 cookies 和正则表达式,这两部分是分开的。出于这个原因,我不会讲太多的细节。需要注意的一个重要的事情是,你需要将.yourdomain.com替换成真实的域。如果你对此有任何问题,在评论中让我知道。
关于客户端时间的一个重要的警告
JavaScript的日期和时间从用户的计算机上获取。这意味着用户可以通过改变机器的时间来影响一个JavaScript时钟。在大多数情况下,这并不重要,但是对于一些超级敏感的情况,有必要从服务器获取时间。这可以使用PHP或Ajax,两者都是超出了本教程的范围。
在任何情况下,从服务器获取时间后,我们可以使用和本教程相同的客户端技术来使用它。
总结
我们已经介绍了如何做一个基础的倒计时时钟和进行有效的显示。我们也学习了计划时钟,绝对与相对时间,跨页面保持时钟的状态。
下一步?
玩时钟代码。尝试添加一些有创意的样式,或新功能(如暂停和恢复按钮)。如果你想出任何酷炫时钟的例子,且你想要和我们分享,或者对以上内容有任何疑问,请在评论中让我知道。
JS 代码编一个倒时器的更多相关文章
- 18 行 JS 代码编一个倒时器
有时候在生活中,你需要一个JavaScript倒计时时钟,而不是一个末日装置设备.不管你是否有一次约会,销售.促销.或者游戏,你可以受益于使用原生JavaScript构建一个时钟,而不是拿到一个现成的 ...
- 几百行代码实现一个 JSON 解析器
前言 之前在写 gscript时我就在想有没有利用编译原理实现一个更实际工具?毕竟真写一个语言的难度不低,并且也很难真的应用起来. 一次无意间看到有人提起 JSON 解析器,这类工具充斥着我们的日常开 ...
- 使用jq把js代码封装一个自己的插件
为什么要把js功能封装成插件呢?我觉得有以下几点吧 1.最基本的原因就是便于代码复用. 2.便于维护和管理. 3.提升自身的能力. 4.避免各个相同功能组件的干扰,以及一些作用域会相互影响的问题. j ...
- 获取网页js代码的一个方法
这个是看了别人的代码,稍加修改而成的.怕时间长忘了,在这里记一笔: console.log(require(["foo:bar.js"]).prototype.someMethod ...
- 原生JS代码实现一个Ajax异步请求
异步加载的方式 (1) defer,只支持IE (2) async: (3) 创建script,插入到DOM中,加载完毕后callBack 实现ajax之前必须要创建一个 XMLHttpRequest ...
- 最新的JavaScript核心语言标准——ES6,彻底改变你编写JS代码的方式!【转载+整理】
原文地址 本文内容 ECMAScript 发生了什么变化? 新标准 版本号6 兑现承诺 迭代器和for-of循环 生成器 Generators 模板字符串 不定参数和默认参数 解构 Destructu ...
- 最新的JavaScript核心语言标准——ES6,彻底改变你编写JS代码的方式!
原文地址 迁移到:http://www.bdata-cap.com/newsinfo/1741515.html 本文内容 ECMAScript 发生了什么变化? 新标准 版本号6 兑现承诺 迭代器和f ...
- node源码详解(四) —— js代码如何调用C++的函数
本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource4 本博客同步在https://cnodejs.o ...
- JS代码指导原则
一.什么是平稳退化? 如果含有JS代码的网页在用户浏览器不支持JS(或者禁用JS)时,用户仍然能够顺利浏览(网站功能正常,只是视觉效果可能差一些),那么这个网页就能够平稳退化 网页能够平稳退化是很必要 ...
随机推荐
- POJ 1724 Roads
题意:有R条路,每条路都有一定的路长和花费,问在总的花费小于一定的值的情况下,从1到N的最短路程 注意:这里两点之间单向边,且可能存在很多条路,所以只能用邻接表存储.思路:用dijks ...
- java基础知识回顾之javaIO类--RandomAccessFile类
java.io 类 RandomAccessFile java.lang.Object java.io.RandomAccessFile1.该类不是IO流中的子类.2.该类既能读又能写.3.该对象内部 ...
- IOS NSPredicate 查询、搜索
简述:Cocoa框架中的NSPredicate用于查询,原理和用法都类似于SQL中的where,作用相当于数据库的过滤取. 最常用到的函数 + (NSPredicate *)predicateWith ...
- Jmeter 快速入门教程(二)--创建简单web测试
[版权所有: whoistester.com & jmeter.cf] http://wenku.baidu.com/linkurl=9zc4VHe6vUUeMdDZPpNsRehkazZFw ...
- Oracle 6 - 锁
Oracle锁没有额外的开销?Oracle的锁是怎么实现的?因为其他数据库,锁都是一种稀有资源和开销. 答:代码级实现?? 没有锁的话,并发更新就会有丢失更新的问题. 悲观锁和乐观锁 悲观锁一般用于有 ...
- emms指令在MMX指令中的作用
emms指令在MMX指令中的作用 转自:http://blog.csdn.net/psusong/archive/2009/01/08/3737047.aspx MMX和SSE都是INTEL开发的基于 ...
- Android:AlertDialog对话框
1.简单的ALertDialog: Dialog alertDialog = new AlertDialog.Builder(this) .setTitle("标题") .setM ...
- 【Spring】关于Boot应用中集成Spring Security你必须了解的那些事
Spring Security Spring Security是Spring社区的一个顶级项目,也是Spring Boot官方推荐使用的Security框架.除了常规的Authentication和A ...
- iosblock用法
看了很多的block用法,还是小糊涂. 最后还是自己尝试吧. #import "FirstViewController.h" @interface FirstViewControl ...
- php整理(四): mysql
PHP学习(四)---PHP与数据库MySql 主要有以下的内容: 1.怎么连接数据库 2.怎么操作数据库 (1)怎么执行sql语言 (2)怎么处理返回的结果集 方法一:面向过程(已经过时,只是了解) ...