07
07月
JS+定时器实现倒计时程序
倒计时程序是我们在日常生活中比较广泛的一种应用。通常可以精确到毫秒,也可以是秒,分钟,或者小时,天等。本项目中所要完成的倒计时程序的应用场景主要是PPT演讲,各类比赛等只需要精确到秒或分钟的情况。
项目介绍
倒计时程序是我们在日常生活中比较广泛的一种应用。通常可以精确到毫秒,也可以是秒,分钟,或者小时,天等。本项目中所要完成的倒计时程序的应用场景主要是PPT演讲,各类比赛等只需要精确到秒或分钟的情况。
本项目中的倒计时程序主要实现如下功能:
该倒计时程序最终的实现效果如图11-4所示。

开发思路
首先来看看页面布局,整个页面分成三个部分,头部主要是一个LOGO和文字信息,底部主要是版权声明信息,本持上来说都是我们熟悉的方法,没有什么好探讨的。主要看看中部的主体功能实现部分,我们通过使用图标的方式来模拟五个按钮的点击操作。同时使用一个文本框来完成倒计时总数的输入和修改。倒计时的显示只需要使用标准DIV结合innerHTML属性的使用即可完成修改。
接下来我们来分析一下关于时间总数的输入和减少,增加的功能应该如何来实现。首先,确认一下规则,时间总数应该至少1分钟,不能低于1分钟,不应该允许出现小数。其次,按增加按钮时,必然我们可以一直将时间增加上去,那么是否有一个最大时间呢?通过下面的时分钞的倒计时显示,我们可以知道,最多能显示的就是99小时59分钟,所以计算下来,该文本框能够允许输入的最大值应该为:99*60+59=5999分钟。
再一方面,由于该文本框是可读写的,用户可以直接输入内容,所以我们必须要限制用户只能输入数字,这方面的技术前面讲解正则表达式时已经跟大家演示过用法,此处不再赘述。
再次,关于倒计时的“暂停”功能,如果按照常规思路,无非就是简单的调用clearInterval()函数即可。但是这里有个问题需要特别注意,点击暂停后我们再点击开始,如果简单地使用这种方式,就会出现倒计时的总数量又会从头开始,而不是从倒计时的剩余时间开始。那么如何处理这种情况呢?我们可以通过设置一个标志变量,来记录当前页面的“暂停”按钮是否被点击过。如果点击过,则“开始”按钮不直接从文本框中读取总时间,而是直接读取剩余时间作为再次开始的总数。否则,直接读取文本框的数值作为总时间。
最后,最重要也是最核心的功能,“开始”按钮实现倒计时,这里面的逻辑相对要复杂一点,不但牵涉到剩余小时数,分钟数,秒钟数的计算,还有数值每一秒种通过判断决定是否减掉1,同时还包括分钟和秒钟在00和59的之间的切换等。听起来是一个复杂的事情,但是笔者给大家一个简单的解决方案,就是将总时间数换算成秒,然后每一秒将该数值减1。至于小时,分钟和秒钟数的切换,只需要通过当前的总秒数来对小时(3600秒),分钟(60秒)等求余即可得出。这样我们就可以将相对复杂的逻辑判断变成一个简单的数学运算。
代码实现
先完成页面的布局。由于页面中元素相对比较多,所以也期望通过本练习让大家对DIV+CSS的布局进行巩固和强化。本布局代码并不代表唯一答案,所以仅供读者参考:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>倒计时工具</title> <style> body { background-image: url('timer/background.jpg'); margin-top: 20px; color: #f0f0f0; font-family: 微软雅黑; } .top { border: solid 1px #ff3300; border-radius: 10px; width: 900px; height: 150px; margin: 0 auto; padding-top: 20px; } .top .logo { float: left; width: 300px; text-align: center; } .top .text { float: left; width: 580px; text-align: center; font-size: 28px; } .main { border: solid 1px #f0f0f0; border-radius: 10px; width: 900px; height: 390px; margin: 0 auto; padding-top: 20px; } #total { width: 150px; height: 45px; border: solid 1px #f0f0f0; border-radius: 8px; font-size: 32px; text-align: center; } .timer-box { border: solid 0px #f30; width: 620px; margin: 0 auto; height: 170px; text-align: center; margin-top: 20px; } .main .count-box { width: 550px; margin: 0 auto; height: 70px; text-align: center; padding-top: 10px; } .main .count { float: left; width: 200px; line-height: 60px; padding-top: 10px; } .main .unit { float: left; width: 120px; font-size: 30px; line-height: 70px; } .timer-box .dash { width: 80px; font-size: 100px; float: left; text-align: center; font-weight: bold; } .timer-box .timer { width: 150px; font-size: 120px; float: left; text-align: center; } .button-box { border: solid 0px #f30; width: 550px; margin: 0 auto; height: 150px; text-align: center; } .icon { float: left; width: 100px; } .icon img:hover { opacity: 0.7; cursor: pointer; } .bottom { border: solid 1px #f0f0f0; border-radius: 10px; width: 900px; height: 55px; margin: 0 auto; padding-top: 10px; text-align: center; font-size: 20px; } </style> </head> <body> <div> <div> <img src="timer/logo.jpg" style="width: 130px;"> </div> <div> 蜗牛学院-学员活动专用倒计时工具<p/><p/>祝各位参赛选手取得优秀成绩! </div> </div> <p/> <div> <div> <div> <img src="timer/minus.png" width="70" onclick="minus();"/> </div> <div> <input type="text" id="total" value="10" onkeyup="check()"/> </div> <div> 分钟 </div> <div style="float: left; width: 100px;"> <img src="timer/plus.png" width="70" onclick="plus();"/> </div> </div>
<div> <div id="hour">00</div> <div>-</div> <div id="minute">00</div> <div>-</div> <div id="second">00</div> </div> <div> <div style="float: left; width: 200px; padding-top: 20px;"> <img src="timer/pause.png" width="60" onclick="pause();" /> </div> <div style="float: left; width: 100px;"> <img src="timer/start.png" width="90" onclick="start();"/> </div> <div style="float: left; width: 200px; padding-top: 20px;"> <img src="timer/refresh.png" width="60" onclick="refresh();"/> </div> </div> </div> <p/> <div> 技术支持:成都蜗牛创想科技有限公司(蜗牛学院), <span style="font-size: 28px;">http://www.woniuxy.com</span> </div> <audio id="done" preload="auto"> <source src="timer/done.mp3" type="audio/mp3"/> </audio> </body> </html> |
接下来我们实现针对分钟数的减少和增加两个按钮的代码功能,代码如下:
// 增加1分钟,到最大值5999 function plus() { var total = parseInt(document.getElementById("total").value); if (total > 5998) document.getElementById("total").value = 5999; else document.getElementById("total").value = total + 1; }
// 减少1分钟,到最小值1 function minus() { var total = parseInt(document.getElementById("total").value); if (total < 2) document.getElementById("total").value = 1; else document.getElementById("total").value = total - 1; } |
同样的,由于文本框是用户可以任意输入值的,所以我们必须响应文本框的onkeyup事件,通过正则表达式来限制用户只能输入数字,代码如下:
// 检查用户的输入类型,只允许输入1~4位数字 function check() { var total = document.getElementById("total"); var input = total.value; var pattern = new RegExp("^\\d{1,4}$"); if (!pattern.test(input)) { total.value = input.substring(0, input.length-1); } } |
现在我们来看看最核心的倒计时实现代码。首先,在实现倒计时代码之前,我们有必要定义一批全局变量,因为有多个函数可能都会用到这批全局变量,用于控制倒计时的开始和暂停等,代码如下:
<script>
// 定义一批全局变量 var interval = null; //计时器对象,用于暂停 var totalSecond = 0; //总的倒计时秒数 var isPaused = false; //是否点击了暂停 var isStarted = false; //是否已经开始倒计时 </script> |
接下来我们基于上述的全局变量,和前面给大家整理的开发思路,来实现开始计时的核心代码,参考代码如下:
function start() { isStarted = true; //指示已经开始 var totalMinute = parseInt(document.getElementById("total").value); // 如果isPaused的值false,说明没有暂停过,则是全新的倒计时开始 if (isPaused == false) totalSecond = totalMinute * 60; // 开始调用定时器对象完成倒计时(按秒为单位) interval = setInterval("timerDown()", 1000); }
// 倒计时核心程序 function timerDown() { // 如果倒计时已经完成,则暂停且播放音乐 if (totalSecond <= 0) { clearInterval(interval); document.getElementById('done').play(); } // 如果时分秒等数字只有一位时,前面补0 var hour = Math.floor(totalSecond/3600); if (hour < 10) hour = "0" + hour; var minute = Math.floor((totalSecond-hour*3600)/60); if (minute < 10) minute = "0" + minute; var second = totalSecond % 60; if (second < 10) second = "0" + second; document.getElementById("hour").innerHTML = hour.toString(); document.getElementById("minute").innerHTML = minute.toString(); document.getElementById("second").innerHTML = second.toString(); totalSecond--; // 让总秒数减1 } |
最后,还有两个简单的功能,暂停和刷新,代码如下:
// 暂停计时 function pause() { if (isStarted) isPaused = true; clearInterval(interval); }
// 刷新页面,重新载入 function refresh() { window.location.reload(); } |
上述代码已经很好地完成了我们预定的功能,由于代码量较大,所以本项目不再单独贴出所有代码。事实上比起代码本身来,大家对于整个过程的工作原理和解决方案的理解才是最核心最重要的部分。要能够举一反三,要能够解决实际问题,那么这些基本功的训练远胜于将代码跑通。
思维拓展
既然我们可以完成一个倒计时程序,我们当然也可以完成一个闹钟,或者一个秒表,但是跟定时器有关的东西都可以利用相似的原理来完成。通过本项目的实战,我们可以看到,如何使用相对简单的解决方案来处理问题,而不是将一个本身听起来逻辑有点复杂的算法用代码实现的时候处理得更加复杂。
另外一个方面,但凡是我们可以让用户进行手工输入的地方,一定要做好充分的容错处理,不给用户犯错误的机会。只有这样,才可以保证我们的程序稳定可靠的运行,无论是大系统还是小应用,这些意识和关注点其实都是一样的。而且为了提高用户体验,我们不应该等待用户输入错误了才提示一个错误信息,而是直接不给用户犯错误的机会。当然,读者可能会问,那既然这样,在本项目中我们直接将输入总分钟数的文本框设置为“只读”不就可以了吗?这样原则上来说是可行的,但是会存在一个严重的问题,用户体验会变得极差。比如我们需要设置900分钟的倒计时,那么这个时候如果我们的默认值为10分钟,用户就必须要点击“增加”按钮890次才行,这显然是不合乎用户使用习惯的。
所以,当我们真正去研发一个产品的时候,一定要站在用户的角度来考虑问题,一切的技术都是为用户服务的。
为了答谢大家对蜗牛学院的支持,蜗牛学院将会定期对大家免费发放干货,敬请关注蜗牛学院的官方微信。

版权所有,转载本站文章请注明出处:蜗牛学苑,
https://www.woniuxy.cn/article/2