18 行 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,两者都是超出了本教程的范围。
在任何情况下,从服务器获取时间后,我们可以使用和本教程相同的客户端技术来使用它。
总结
我们已经介绍了如何做一个基础的倒计时时钟和进行有效的显示。我们也学习了计划时钟,绝对与相对时间,跨页面保持时钟的状态。
下一步?
玩时钟代码。尝试添加一些有创意的样式,或新功能(如暂停和恢复按钮)。如果你想出任何酷炫时钟的例子,且你想要和我们分享,或者对以上内容有任何疑问,请在评论中让我知道。