纯js实现倒计时

本文介绍了如何使用JavaScript实现页面倒计时功能。通过分析原始代码的问题,包括缺乏复用性、setInterval可能导致的队列过多以及不符合面向对象思想,作者提出了解决方案。修复这些问题后,代码变得更加优化,增加了参数以提高复用性,并使用setTimeout替代setInterval来避免队列问题。同时,通过定义that变量处理this指向,改进了面向对象的设计。

通过js实现页面的倒计时功能。

思路: 传入一个秒数c,c/60可以得到分钟m, c%60可以得到显示的秒数s,同理,再将m/60可是得到小时数, m/%可以得到分钟数。通过setInterval每次将总秒数-1,并将计算所得时间显示到页面上。

第一版的肮脏代码如下, 可以作为反面教材思考一下

<html>
    <head>
        <title>Tomato</title>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script type="text/javascript">
			var vTimeLength = 5;
			var vHour;
			var vMinutes;
			var vSeconds;
			var vRemainingTime;
			function countDown(){
				vTimeLength = vTimeLength - 1;
				vMinutes = Math.floor(vTimeLength/60);
				vSeconds = Math.floor(vTimeLength%60);
				if (vMinutes >= 60){
					vHour = Math.floor(vMinutes/60);
					var vMinutesNew = Math.floor(vMinutes%60);
					vRemainingTime = vHour + ":" + vMinutesNew + ":" + vSeconds;
				} else {
					vRemainingTime = vMinutes + ":" + vSeconds;
				}
				document.getElementById("div_countDown").innerHTML = vRemainingTime;
				if (vTimeLength < 1) {
					alert('do sth');
				}
			}
			
        </script>
    </head>
    <body>
        <div id="div_countDown"></div>
		<script type="text/javascript">
			setInterval("countDown()", 1000);
		</script>
    </body>
</html>
缺陷: 1、定义了众多的全局变量, 

2、没有复用性, 

3、setInterval容易导致队列过多, 结束事件如果是非阻塞事件, 倒计时会继续执行出现负数, 

4、不符合面向对象思想。。。

针对缺陷1的解决方案是, 定义一个函数, 将相关全局变量放到函数内部,使之成为局部变量

针对缺陷2:为函数指定参数,提高复用性。 这里定义了3个参数vTimeLength为倒计时总秒数,showTagId为显示到页面元素的id, callback为倒计时结束后的回掉方法

针对缺陷3:用setTimeout替代setInterval

优化后的代码如下:

<html>
    <head>
        <title>countdown</title>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script type="text/javascript">
			function countDown(vTimeLength, showTagId, callback) {
				var vHour;
				var vMinutes;
				var vMinutesNew
				var vSeconds;
				var vRemainingTime;
				function countDownInner(vTimeLength){
					vMinutes = Math.floor(vTimeLength/60);
					vSeconds = Math.floor(vTimeLength%60);
					if (vMinutes >= 60){
						vHour = Math.floor(vMinutes/60);
						vMinutesNew = Math.floor(vMinutes%60);
						vRemainingTime = vHour + ":" + vMinutesNew + ":" + vSeconds;
					} else {
						vRemainingTime = vMinutes + ":" + vSeconds;
					}
					document.getElementById(showTagId).innerHTML = vRemainingTime;
					vTimeLength = vTimeLength - 1;
					if (vTimeLength > 0) {
						setTimeout(function(){countDownInner(vTimeLength);}, 1000);
					} else {
						callback();
					}
				}
				countDownInner(vTimeLength);
			}
			
        </script>
    </head>
    <body>
        <div id="div_countDown"></div>
		<script type="text/javascript">
			countDown(5, "div_countDown", function(){alert('do sth');});
		</script>
    </body>
</html>

这里有一点需要注意
setTimeout(function(){countDownInner(vTimeLength);}, 1000);
第一次我将此句写成了
setTimeout(countDownInner(vTimeLength), 1000);
结果函数直接执行了, 没有等待1秒的时间。如果没有入参, 即setTimeout("countDownInner()", 1000); 则可正常执行。

至于前面提到的不够面向对象的缺陷, 也是刚刚接触, 这里贴出代码,希望能够互相交流

<html>
    <head>
        <title>count_down</title>
        <script type="text/javascript">
        var countDown = {
            flag: true, 
            hour: 0,
            minutes: 0,
            minutesNew: 0,
            seconds: 0,
            show: 0,
            current: 0,
            length: 0,
            showTagId: null,
            // callback: null,
            countDownInner: function(vTimeLength){
        		if (!this.flag) {
                    return;
                }
                var that=this;
                this.current = vTimeLength;
                minutes = Math.floor(vTimeLength/60);
                seconds = Math.floor(vTimeLength%60);
                if (minutes >= 60){
                    hour = Math.floor(minutes/60);
                    minutesNew = Math.floor(minutes%60);
                    show = hour + ":" + minutesNew + ":" + seconds;
                } else {
                    show = minutes + ":" + seconds;
                }
                document.getElementById(this.showTagId).innerHTML = show;
                vTimeLength = vTimeLength - 1;
                if (vTimeLength > 0) {
                    setTimeout(function(){that.countDownInner(vTimeLength);}, 1000);
                } else {
                	setTimeout(function(){that.callback();}, 1000);
                }
            },
            run: function(vTimeLength, showTagId, callback) {
            	if (!this.flag) {
            		this.flag = true;
            		this.countDownInner(this.current);
            	} else if (showTagId) {
                    this.length = vTimeLength;
                    this.showTagId = showTagId;
                    this.callback = callback;
                    this.countDownInner(vTimeLength);    
                }
            },
            stop: function(){
            	this.flag = false;
            }, 
            restart: function(){
                this.flag = true;
                this.countDownInner(this.length);
            }
        };

        function countDownStart() {
            countDown.run();
        }
        function countDownStop() {
            countDown.stop();
        }
        </script>
    </head>
    <body>
        <div id="div_countDown"></div>
        <script type="text/javascript">
        	countDown.run(5, 'div_countDown',function(){alert('12')});
        </script>
        <span>
            <button onclick="countDownStart();">start</button>
            <button onclick="countDownStop();">stop</button>
        </span>
    </body>
</html>

一个难点是this的使用, 在函数内部, this是调用当前函数范围,所以setTimeout(function(){this.countDownInner(vTimeLength);}, 1000);会出现undefined。

解决方案是定义一个that变量接收外部函数的this指针,然后通过that即可调用外部域。





评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值