清除图库动画期间超时

发布于 2024-11-28 22:35:06 字数 1226 浏览 2 评论 0原文

我创建了一个具有自动播放功能的画廊。

当画廊停止播放动画并且我们将鼠标悬停在画廊上时,一切都会按预期进行。

但我遇到了一个奇怪的问题:

当画廊动画时 -->将鼠标悬停在画廊上时,clearTimeout 似乎无法正常工作,并且在 mouseleave 上,画廊表现得很奇怪
或者发生了我无法理解和解决的奇怪冲突。我回到几天前制作的另一个画廊,具有类似的功能,并且遇到了同样的问题。

我在这里遗漏了一些重要的东西

有问题的画廊:jsFiddle

var myTimeOut;

/////// ANIMATION /////////////   
    function animation(cb){         
            $('#slider').animate({left: '-=600' },800, cb);
    }      
    /////// AUTO SLIDE ////////////
    function auto() {
        myTimeOut = setTimeout(function() {
            animation(function(){
                auto();                   
            });   
        }, 2000);
    }
    auto();

以及我如何我正在尝试暂停它:

    ///// MOUSE actions //////////   
    $('#galcontainer').mouseenter( function () {
      clearTimeout(myTimeOut);
    });
    $('#galcontainer').mouseleave( function () {
     auto();
    });

编辑

添加“悬停标志”(如答案中所建议的)效果几乎很好,但是当“在动画期间快速鼠标进入/鼠标离开”时,可以看到使用此解决方案的一个小错误。
解决该问题的方法可以是在 mouseleave 处添加 $('#slider').stop() 。这不是一个很好的解决方案。
我还能做什么?

I created a gallery with auto-play.

When the gallery STOP it's animation and we hover the gallery, all works as expected.

But I am getting a strange issue:

While the gallery is animating --> hovering the gallery, the clearTimeout seem not to work correctly and on mouseleave the gallery behave strangely
or it's happening a strange conflict I cannot understand and resolve. I went back to an other gallery I made a couple of days before fith a similar functionality and I encountered the same issue.

I am missing something crucial here

THE GALLERY IN QUESTION: jsFiddle

var myTimeOut;

/////// ANIMATION /////////////   
    function animation(cb){         
            $('#slider').animate({left: '-=600' },800, cb);
    }      
    /////// AUTO SLIDE ////////////
    function auto() {
        myTimeOut = setTimeout(function() {
            animation(function(){
                auto();                   
            });   
        }, 2000);
    }
    auto();

and how I'm trying to pause it:

    ///// MOUSE actions //////////   
    $('#galcontainer').mouseenter( function () {
      clearTimeout(myTimeOut);
    });
    $('#galcontainer').mouseleave( function () {
     auto();
    });

EDIT

Adding a 'hover flag' (as suggested in the answers) works almost great, but a small bug using this solution is visible when 'fast mouseenter/mouseleave DURING the animation.

A fix to that issue could be adding a $('#slider').stop() at mouseleave. Not a great solution.
What else can I do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

能怎样 2024-12-05 22:35:06

当动画正在进行时,有时不会触发 mouseout 事件,因此 pause 变量不会设置为 false。当触发下一个 mouseoever 事件时,因为暂停不是 false ,它将再次设置超时。我只是确保在设置新的超时之前清除之前的所有超时。

看看这个工作演示。

http://jsfiddle.net/8Lzxs/3/

When the animation is in progress sometimes the mouseout event is not getting triggered so pause variable is not set to false. when next mouseoever event is triggered since pause is not false it will again set the timeout. I just made sure we clear any previous timeout before setting the new one.

Take a look at this working demo.

http://jsfiddle.net/8Lzxs/3/

荆棘i 2024-12-05 22:35:06

问题是在动画播放过程中,没有超时停止的情况。一个超时已经触发,另一个超时在动画完成之前不会创建。因此,如果您在动画进行时将鼠标悬停,动画将继续。您可以使用一个标志来解决这个问题,以判断动画是否应该停止。如果设置了该标志,则自动返回并且不会设置另一个超时。

http://jsfiddle.net/PXVSW/6/

The problem is that during the animation, there is no timeout to stop. The one timeout has already fired and other is not created until the animation completes. Because of this, if you hover when the animation is in progress, the animation continues. You can solve this with a flag to tell whether or not the animation should be stopped. If the flag is set, auto returns and does not set another timeout.

http://jsfiddle.net/PXVSW/6/

萌辣 2024-12-05 22:35:06

在没有深入研究代码的情况下,我通过添加一些额外的检查来修复它。

首先,我这样做是为了不用担心超时标识符被替换。我使用一个数组,以防多个事件堆叠在一起,并清除该数组中的所有超时。

其次,我添加了一个 stop() 值并使其在“stopped”为 true 时动画不会运行。

这是我的更改的小提琴: http://jsfiddle.net/6WhNw/

Without digging too deeply into your code, I fixed it by adding a couple of extra checks.

First, I made it so there's no worry about the timeOut identifier getting replaced. I use an array in case multiple events get stacked on top of each other, and clear all of the timeouts in that array.

Second, I added a stop() value and made it so the animation won't run if stopped is true.

Here's the fiddle with my changes: http://jsfiddle.net/6WhNw/

我不会写诗 2024-12-05 22:35:06

如果动画运行时鼠标进入,则不起作用。这是因为计时器已经启动,并且动画结束时将在完成时开始一个新的动画。我能想到的解决这个问题的最少重写是,当您将鼠标悬停在自动功能检查时设置一个全局标志,这样如果设置了该全局标志,它就不会启动新的动画。

您可以在此处查看 hoverFlag 解决方案:http://jsfiddle.net/jfriend00/EaKnj /

一个有趣的测试案例是让鼠标在动画运行时进入。

It doesn't work if your mouse enters while the animation is running. That's because the timer has already fired and the end of the animation is going to start a new one when it completes. The least rewrite I can think of to solve this would be to set a global flag when you're hovered that the auto function checks so it won't start a new animation if that global flag is set.

You can see the hoverFlag solution here: http://jsfiddle.net/jfriend00/EaKnj/.

An interesting case to test is to make your mouse enter when the animation is running.

思念绕指尖 2024-12-05 22:35:06

我发现 iOS 6 上的滚动(嗯,也是一种动画)似乎会导致同样的问题:只要视图滚动,超时就不会被可靠地清除。

我认为这是一个 iOS Bug,并且 - 就我而言 - 找到了一个不使用 set 和clearTimeout 的解决方案。

在(几个)Android Stock 浏览器和 Chrome 中无法重现相同的问题。

I found that scrolling (which is, well, a sort of animation too) on iOS 6 seems to cause the same problem: timeouts are not cleared reliably as long as a view scrolls.

I considered this an iOS Bug and - in my case - found a solution not using set and clearTimeout.

The same issue couldn't be reproduced in (several) Android Stock Browsers and Chrome.

被你宠の有点坏 2024-12-05 22:35:06

您需要使用 setInterval 而不是 setTimeout。由于动画正在调用回调,因此它会一遍又一遍地调用动画。

http://jsfiddle.net/PXVSW/7/

var galW =  $('#gallery').width() ,
    imgN =  $('#slider img').length ,
    direction,      // direction ( -=  or  0- ) // set initially to 'null','undefined'
    counter = 1,    // counter
    myTimeOut;       // global setTimeout

$('#slider').width(galW * imgN);

/////// ANIMATION /////////////   
function animation(){                 // cb : makes animation accept a callback
        $('#slider').animate({left: direction+''+galW},800);
}  

/////// AUTO SLIDE ////////////
function auto() {
    myTimeOut = setInterval(function() {
        if ( counter != imgN){           // if counter != '4' (N of Images)
            counter++                    // add '1' to counter
            direction = '-=';            // set direction to go 'left' 
        }
        else{
            counter = 1;
            direction = '0-';            // trick - to bring slider to '0px' left (start position)
        }
        animation();   
    }, 2000);
}
auto();

///// MOUSE STATE //////////   
$('#galcontainer').mouseenter( function () {
  clearInterval(myTimeOut);
});
$('#galcontainer').mouseleave( function () {
 auto();
});

You need to be using setInterval instead of setTimeout. Since the animation was calling the callback, it would call the animation over and over.

http://jsfiddle.net/PXVSW/7/

var galW =  $('#gallery').width() ,
    imgN =  $('#slider img').length ,
    direction,      // direction ( -=  or  0- ) // set initially to 'null','undefined'
    counter = 1,    // counter
    myTimeOut;       // global setTimeout

$('#slider').width(galW * imgN);

/////// ANIMATION /////////////   
function animation(){                 // cb : makes animation accept a callback
        $('#slider').animate({left: direction+''+galW},800);
}  

/////// AUTO SLIDE ////////////
function auto() {
    myTimeOut = setInterval(function() {
        if ( counter != imgN){           // if counter != '4' (N of Images)
            counter++                    // add '1' to counter
            direction = '-=';            // set direction to go 'left' 
        }
        else{
            counter = 1;
            direction = '0-';            // trick - to bring slider to '0px' left (start position)
        }
        animation();   
    }, 2000);
}
auto();

///// MOUSE STATE //////////   
$('#galcontainer').mouseenter( function () {
  clearInterval(myTimeOut);
});
$('#galcontainer').mouseleave( function () {
 auto();
});
我只土不豪 2024-12-05 22:35:06

问题:在动画期间 mouseenter 上,jQuery .animate() 回调 cb 已经在队列中(即使调用了clearTimeout,也会调用另一个 auto() ,这将触发后续运行等)。

使用 setInterval 并利用所有这些回调是关键:

jsFiddle 演示

$(function(){                 // DOM ready shorthand
    var $sli =  $("#slider"), // Cache elements you plan to reuse
        galW =  $('#gallery').width(),
        imgN =  $sli.find('img').length,
        counter = 0,          // set it to index 0!
        itv;                  // setInterval (scope var)
    
    $sli.width(galW * imgN);

    function anim() {
      ++counter; counter%=imgN;                       // Incr.counter; and wrap-around
      $sli.stop().animate({left: -galW*counter},900); // width*counter = px position
    }
    function autoSlide() {
        itv = setInterval(anim, 3000);
    }
    autoSlide();
    
    ///// MOUSE STATE //////////   
    $sli.hover(function(){ clearInterval(itv); }, autoSlide);
});
#galcontainer{
    position:relative;
    margin:20px auto;
    width:600px;
}
#gallery{
    position:relative;
    overflow:hidden;
    width:600px;
    height:240px;
}
#slider{
    position:absolute;
    top:0px;
    left:0px;
}
#slider img{
    float:left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="galcontainer">    
    <div id="gallery">    
        <div id="slider">
            <img src="http://dummyimage.com/600x240/479/fff"/>
            <img src="http://dummyimage.com/600x240/636/fff"/>
            <img src="http://dummyimage.com/600x240/587/fff"/>
            <img src="http://dummyimage.com/600x240/447/fff"/>
        </div>     
    </div>   
</div>

(关于原始(尚未修改)代码的注释)

带有 "+=""0-"direction 变量是不需要的,因为只有一个方向,因此使用 counter = 0 索引,并使用 Reminder % 运算符进行环绕/重置。另外,

        animation(function(){
            auto();                   
        }); 

可以写成:

       animation(auto);

因为 auto 已经是一个函数。

///// MOUSE STATE //////////   
$('#galcontainer').mouseenter( function () {
  clearInterval(myTimeOut);
});
$('#galcontainer').mouseleave( function () {
 auto();
});

可以与 .hover(fn1, fn2) 方法一起使用(如上面的示例)

The issue: on mouseenter during the animation, the jQuery .animate() callback cb is already in queue (even if the clearTimeout was called, another auto() will be called which will trigger subsequent runs, etc.).

Using setInterval and leveraging all those callbacks is the key:

jsFiddle demo

$(function(){                 // DOM ready shorthand
    var $sli =  $("#slider"), // Cache elements you plan to reuse
        galW =  $('#gallery').width(),
        imgN =  $sli.find('img').length,
        counter = 0,          // set it to index 0!
        itv;                  // setInterval (scope var)
    
    $sli.width(galW * imgN);

    function anim() {
      ++counter; counter%=imgN;                       // Incr.counter; and wrap-around
      $sli.stop().animate({left: -galW*counter},900); // width*counter = px position
    }
    function autoSlide() {
        itv = setInterval(anim, 3000);
    }
    autoSlide();
    
    ///// MOUSE STATE //////////   
    $sli.hover(function(){ clearInterval(itv); }, autoSlide);
});
#galcontainer{
    position:relative;
    margin:20px auto;
    width:600px;
}
#gallery{
    position:relative;
    overflow:hidden;
    width:600px;
    height:240px;
}
#slider{
    position:absolute;
    top:0px;
    left:0px;
}
#slider img{
    float:left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="galcontainer">    
    <div id="gallery">    
        <div id="slider">
            <img src="http://dummyimage.com/600x240/479/fff"/>
            <img src="http://dummyimage.com/600x240/636/fff"/>
            <img src="http://dummyimage.com/600x240/587/fff"/>
            <img src="http://dummyimage.com/600x240/447/fff"/>
        </div>     
    </div>   
</div>

(Aside notes regarding the original (yet modified) code)

The direction variable with "+=" and "0-" is unneeded since there's only one direction, so use a counter = 0 indexed, and wrap-around/reset using the Reminder % operator. Also,

        animation(function(){
            auto();                   
        }); 

can be written like:

       animation(auto);

since auto is already a function.

///// MOUSE STATE //////////   
$('#galcontainer').mouseenter( function () {
  clearInterval(myTimeOut);
});
$('#galcontainer').mouseleave( function () {
 auto();
});

can be used with .hover(fn1, fn2) method (like in the above example)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文