20

I have an interface that makes heavy use of the jQuery slideUp and slideDown effect to expand items in a tri-state kind of way.

onmouseover: function() { 
    this.find('.details', this).slideDown(); 
},
onmouseout: function() { 
    this.find('.details', this).slideUp(); 
}

However, when the user quickly moves the mouse over these interface elements the animations can't keep up and the items will be sliding up and down long after the mouse has left the interface area.

Is there a way to cancel all the queued-up slide animations when the mouse leaves the item's container div?

KyleMit
  • 30,350
  • 66
  • 462
  • 664
Candidasa
  • 8,580
  • 10
  • 30
  • 31

7 Answers7

34

I believe you should be able to just add a .stop() and it'll take care of that for you:

onmouseover: function() { 
    this.find('.details', this).stop().slideDown(); 
},
onmouseout: function() { 
    this.find('.details', this).stop().slideUp(); 
}
KyleMit
  • 30,350
  • 66
  • 462
  • 664
Matt Crest
  • 560
  • 1
  • 5
  • 12
  • 2
    Also make sure you're using jQuery 1.7.2 or later, as previously there was a bug when using slideUp() and slideDown() with stop(), where if you quickly hovered on and off a couple of times, your element would suffer weird height issues. – jackocnr May 11 '12 at 20:15
  • 2
    I observe these weird issues even with jQuery 1.7.2... are you sure about the version number? – Joachim Breitner Sep 17 '12 at 15:29
  • I am getting the same issues in 1.9. The key is to remove `.stop()` from `slideDown()`. If it's on there, `jQuery` will sometimes just jump directly to the target height, "stopping" the animation. – jclancy Aug 02 '13 at 18:31
  • 2
    I had the same issue with jquery-1.8.3 either using `clearQueue()` or `stop()` ... Finally used `.stop(true, true)` ! – Stphane Oct 01 '13 at 14:06
21

The answer you really want is a combination of all the other three answers.

$("...").hover(function() {
  $(this).stop(true, true).slideDown();
}, function() {
  $(this).stop(true, true).slideUp();
});

You want the trues in the stop because these clear the pending animation queues. If you don't use these, you'll find moving the mouse quickly and repeatedly across the element will produce buggy results.

halfer
  • 19,824
  • 17
  • 99
  • 186
Andrew Bullock
  • 36,616
  • 34
  • 155
  • 231
8

Generally speaking you want to call stop() when starting such an animation:

$("...").hover(function() {
  $(this).stop().slideDown();
}, function() {
  $(this).stop().slideUp();
});

That should be sufficient to avoid long-running animation queues.

You can also use $.clearQueue() to globally clear animations that haven't yet begun.

Also, if you're setting these on mouseover() and mouseout() it is arguably clearer to simply use the hover() event instead.

cletus
  • 616,129
  • 168
  • 910
  • 942
6

It is also much better if you put parameters in stop(), just like this: stop(true,true)...

falsarella
  • 12,217
  • 9
  • 69
  • 115
user403151
  • 61
  • 1
  • 1
4

In my case, I was also looking for a .stop() solution to the up and down extensive animation queue. However, it still didn't solve, because it wasn't smooth, and it was buggy, making it not to slide down anymore.

Hence, I came with a solution that is not related to cancel queues, but it might help some of you. The solution is about sliding it down or up just when the animation target is not currently being animated.

$("#trigger").on({
    mouseover: function() {
        $("#animationTarget").not(":animated").slideDown();
    },
    mouseleave: function() {
        $("#animationTarget").not(":animated").slideUp();
    }
});
falsarella
  • 12,217
  • 9
  • 69
  • 115
1

You could do something like the following: http://jsfiddle.net/3o2bsxo6/3/

JavaScript

$('h5').each(function(){
    $(this).unbind('mouseover'); //unbind previous events (prevent repeats)
    $(this).unbind('mouseout');

    $(this).on('mouseover',function(){
        if(!$(this).next('.details').is(':visible')){ //if not visible
             $(this).next('.details').slideDown();   //slidedown                        
        }
    })  
    $(this).on('mouseout',function(){
        if($(this).next('.details').is(':visible')){ //if visible
             $(this).next('.details').slideUp();    //slideup                           
        }
    })      
})

html:

<h5>Hover To Slide</h5>
<p class="details">
However, when the user quickly moves the mouse over these interface elements the animations can't keep up and the items will be sliding up and down long after the mouse has left the interface area.    
</p>
<h5>Hover To Slide</h5>
<p class="details">
However, when the user quickly moves the mouse over these interface elements the animations can't keep up and the items will be sliding up and down long after the mouse has left the interface area.    
</p>
<h5>Hover To Slide</h5>
<p>
However, when the user quickly moves the mouse over these interface elements the animations can't keep up and the items will be sliding up and down long after the mouse has left the interface area.    
</p>

CSS:

p{
    display:none;
}
maudulus
  • 10,627
  • 10
  • 78
  • 117
0

Similar query was posted in this thread. Using

stop(true, false)
you can achieve the effect without bugs.
$('#YourDiv').on('mouseenter', function(){
   $(this).next().slideDown(250).stop(true, false).slideDown()  
});

I've assumed that there is an element after #YourDiv that you want to put slide-up and slide-down animations.

This will jump to the animation of the last event and clear all the pending events in the chain.

Debadatta Meher
  • 83
  • 2
  • 10