想要使用clearInterval停止setInterval,但无济于事

时间:2013-05-23 08:45:54

标签: javascript jquery clearinterval

我所拥有的是一个与keydown事件相关联的元素。

类似问题的答案都指向clearInterval,我无法开始工作。

首先,我使用keyup事件来检查正在按下哪个箭头键:

var counter = 0;

var yPosArray = [];
var right = true;
var done = false;
var leftX;
var rightX;
$(document).keydown (function(e) 
{
    rightX = parseInt(($('#movingObject').css('left')).replace('px','')) + 50;
    leftX = parseInt(($('#movingObject').css('left')).replace('px',''));

    if(e.which == 39)// right
    {
        $('#movingObject').find('img').attr('src','assets/images/mario_right.png');
        right = true;
        $('#xRight').val(rightX);
        $('#xLeft').val(leftX);
        move();
    }
    if(e.which == 37)   //left  
    {
        $('#movingObject').find('img').attr('src','assets/images/mario_left.png');
        right = false;
        $('#xRight').val(rightX);
        $('#xLeft').val(leftX);
        move();
    }
    if(e.which == 38)   //up    
    {
        if($('#movingObject').css('bottom') == '0px' && !false)
        {
            done = true;
            gravity();
            done = false;
        }
    }
});

如上所示,当满足此条件e.which == 37时,将调用方法move()。 move方法的作用如下所示,是增加元素的left样式属性。我有一个计时器的原因是随着时间的推移速度增加,但是当钥匙被释放时,事件应该停止射击。因此,我想调用keyup事件,如上一个代码片段所示。解释将在那里继续。

var speed = 0;
var maxspeed = 0;
var timer;
function move()
{   
     var counter = 0;
     timer = setInterval(function () 
     {
         maxspeed++;
         $('#movingObject').css('left', moveX + maxspeed + 'px');
         ++counter;
    }, 70);
}

如上所示,在创建move函数之前声明了timer变量,并将其设置为setInterval方法。因为变量在根级别,如果这是有意义的,它可以在所有函数中使用。

如下所示,我已启动keyup事件以检查不同的密钥。

$(document).keyup (function(e) 
{
    var posX = parseInt(($('#movingObject').css('left')).replace('px',''));
    if(e.which == 39)// right
    {
        maxspeed = 0;
        clearInterval(timer);
        timer = 0;
    }
    if(e.which == 37)   //left  
    {
        maxspeed = 0;
        clearInterval(timer);
        timer = 0;
    }
    $('#movingObject').css('left', posX + 'px');
});

上面,我使用了clearInterval并尝试将timer设置为等于0,然后继续增加。

这是一个fiddle,其中包含我的代码结构的所有脚本。

为什么会发生这种情况?

2 个答案:

答案 0 :(得分:1)

每次setInterval都会创建一个新的timer,所以当你clearInterval时,你必须清除你创建的所有计时器(可能是其中一些)。看看这个打击:< / p>

var speed = 0;
var maxspeed = 0;
var timer=[];
function move()
{   
     var counter = 0;
     timer.push(setInterval(function () 
     {
         maxspeed++;
         $('#movingObject').css('left', moveX + maxspeed + 'px');
         ++counter;
    }, 70));
}

$(document).keyup (function(e) 
{
    var posX = parseInt(($('#movingObject').css('left')).replace('px',''));
    if(e.which == 39)// right
    {
        maxspeed = 0;
        $.each(timer,function(i,n){
            clearInterval(n);
        });
        timer=[];
    }
    if(e.which == 37)   //left  
    {
        maxspeed = 0;
        $.each(timer,function(i,n){
            clearInterval(n);
        });
        timer=[];
    }
    $('#movingObject').css('left', posX + 'px');
});

答案 1 :(得分:1)

当用户同时按下两个(或更多)键时,可能会发生这种情况。然后你会在没有中间密钥的情况下调用move()来清除一个间隔 - 这意味着你要覆盖第一个的timer间隔id并且永远不能再次停止它,基本上在密钥发生时忘记了它。

如何解决这个问题?有一些选择:

  • 一次只运行一个间隔。这可以通过每timer = setInterval(…)前加clearInterval(timer)来实现(如果已经清除则不会发生任何事情)。

  • 有一组运行间隔。像@jarvanJiang实现它的数组没有多大意义,因为如果只释放一个键(如while(timers.length) clearInterval(timers.pop())),你不想停止所有间隔。也没有一种FIFO队列,其中最早的间隔被清除。

    相反,您需要每个键一个计时器ID - 运行间隔的映射。释放钥匙后,您可以通过在地图中查找来确定要清除的间隔。

  • 实现更好的只是一个间隔game loop,以及一个布尔键的映射,指示当前按下了哪些。这将允许您管理干扰输入,并使动画运行更顺畅。