用定时器做一个发送验证码的倒计时遇到的问题?


当我点击那个向手机发送验证吗的按钮是(#sendsms),给那个按钮加了一个disabled属性,
但是倒计时按钮还是可以点击,多次点击之后就出现问题,当curTime==0时,明明已经clearInterval(timer);了,但还是会不断进入if(curTime==0)里执行。


 $("#sendsms").on("click",function(){
        curTime=countTime;
        var phone=$("#form_phone").val();
        if(phone!=""){

            $("#sendsms").attr("disabled","true");
            $("#sendsms").text(curTime+"秒后可重新发送");
            timer=setInterval(handleTimer, 1000);
        }
    });

    function handleTimer(){
        if(curTime==0){
            clearInterval(timer);
            timer=null;
            $("#sendsms").removeAttr("disabled");
            $("#sendsms").text("重新发送验证码");
        }
        else{
            curTime--;
            $("#sendsms").text(curTime+"秒后可重新发送");
        }
    }

jquery web前端开发 css JavaScript

Nicky 9 years, 9 months ago

 $("#sendsms").on("click",function(){
        curTime=countTime;
        var phone=$("#form_phone").val();
        //每次进入把原来timer清除掉
        if(timer){
            clearInterval(timer);
            timer=null;
        }
        if(phone!=""){
            $("#sendsms").attr("disabled","true");
            $("#sendsms").text(curTime+"秒后可重新发送");

            timer=setInterval(handleTimer, 1000);
        }
    });

    function handleTimer(){
        if(curTime==0){
            clearInterval(timer);
            timer=null;
            $("#sendsms").removeAttr("disabled");
            $("#sendsms").text("重新发送验证码");
        }
        else{
            curTime--;
            $("#sendsms").text(curTime+"秒后可重新发送");
        }
    }

甩葱的小弟弟 answered 9 years, 9 months ago


 1.在click事件中你的判断条件是 `phone!=""` 这是判断手机号是不是空吧?并不是判断是否在进行倒计时。
2.clearInterval(timer); 对 curTime 并无影响,curTime 仍旧是0,当然一直在这个条件语句中。
3.`curTime=countTime;` 建议改成 `var curTime=countTime;

上面我搞错了,真是答非所问。。不知道的还是要查啊。

我跑了一下下面的代码:


 var countTime = 10;
$("button").click(function(){
        curTime=countTime;
        var phone=$("#aaa").val();
        if(phone!=""){
            $("button").attr("disabled","true");
            $("button").text(curTime+"秒后可重新发送");
            timer=setInterval(handleTimer, 1000);
        }
  })
});


function handleTimer(){
        console.log(timer);
        if(curTime==0){
            clearInterval(timer);
            timer=null;
            $("button").removeAttr("disabled");
            $("button").text("重新发送验证码");
        }
        else{
            curTime--;
            $("button").text(curTime+"秒后可重新发送");
        }
}


 <input id="aaa" type="text"  />
<button type="submit" value="Submit" > Submit</button>

是可以的啊,所以我也不知道是什么情况了,建议楼主调试一下或者用console.log()吧,再有问题再贴出来= =

星期日D日耀日 answered 9 years, 9 months ago

请搜索一下setInterval方法,setInterval会创建一个异步线程,返回是这个线程的ID。

多次点击,会创建多个线程。timer被赋值到最后一个线程的ID,停止了的也是最后一个线程。还有其他异步线程在跑着,没有停止。

可以在handleTimer函数中打印一下timer就明白了。

解决办法:
1- 倒数期间,对元素解绑事件。
2- 单一设计模式,判断timer是否被赋值。

方法2:


 var curTime = 0,
    timer = null,
    btn = $('#button');
btn.on('click',function(){
    if(timer === null){
        curTime = 3;
        timer = setInterval(handleTimer, 1000);
    }
});
function handleTimer(){
    console.log(timer);
    if(curTime === 0){
        clearInterval(timer);
        timer = null;
        btn.text('重新发送验证码');
    }else{
        btn.text(curTime + '秒后可重新发送');
        curTime --;
    }
}

看了一下其他答案,均在click中clearInterval清除计时器,这样的确可以修复问题,但是同时存在另外问题:
1- 多次按下btn,多次清除定时器,性能问题。
2- 正在倒计时的时候应该禁用掉功能函数,不应再触发重新倒计时。


 // var timer = null;
$("#sendsms").on("click",function(){
        var phone=$("#form_phone").val();
        if(phone!="" && timer == null){
            curTime=countTime;
            $("#sendsms").attr("disabled","true");
            $("#sendsms").text(curTime+"秒后可重新发送");
            timer=setInterval(handleTimer, 1000);
        }
    });

    function handleTimer(){
        if(curTime==0){
            clearInterval(timer);
            timer=null;
            $("#sendsms").removeAttr("disabled");
            $("#sendsms").text("重新发送验证码");
        }
        else{
            curTime--;
            $("#sendsms").text(curTime+"秒后可重新发送");
        }
    }

只猪走天涯 answered 9 years, 9 months ago

Your Answer