I have a drop down menu. Now when it's slided down to multiple levels, I'd like it to add wait time for like 2 secs, before it disappears, so the user can get back in, when he breaks the .hover()
by mistake.
Is it possible?
my code for the slide:
$('.icon').hover(function() {
$('li.icon > ul').slideDown('fast');
}, function() {
$('li.icon > ul').slideUp('fast');
});
This will make the second function wait 2 seconds (2000 milliseconds) before executing:
$('.icon').hover(function() {
clearTimeout($(this).data('timeout'));
$('li.icon > ul').slideDown('fast');
}, function() {
var t = setTimeout(function() {
$('li.icon > ul').slideUp('fast');
}, 2000);
$(this).data('timeout', t);
});
It also clears the timeout when the user hovers back in to avoid crazy behavior.
This is not a very elegant way of doing this, however. You should probably check out the hoverIntent plugin, which is designed to solve this particular problem.
personally I like the "hoverIntent" plugin:
http://cherne.net/brian/resources/jquery.hoverIntent.html
from the page: hoverIntent is a plug-in that attempts to determine the user's intent... like a crystal ball, only with mouse movement! It works like (and was derived from) jQuery's built-in hover. However, instead of immediately calling the onMouseOver function, it waits until the user's mouse slows down enough before making the call.
Why? To delay or prevent the accidental firing of animations or ajax calls. Simple timeouts work for small areas, but if your target area is large it may execute regardless of intent.
var config = {
sensitivity: 3, // number = sensitivity threshold (must be 1 or higher)
interval: 200, // number = milliseconds for onMouseOver polling interval
over: makeTall, // function = onMouseOver callback (REQUIRED)
timeout: 500, // number = milliseconds delay before onMouseOut
out: makeShort // function = onMouseOut callback (REQUIRED)
};
$("#demo3 li").hoverIntent( config )
Configuration Options
sensitivity:
If the mouse travels fewer than this number of pixels between polling intervals, then the "over" function will be called. With the minimum sensitivity threshold of 1, the mouse must not move between polling intervals. With higher sensitivity thresholds you are more likely to receive a false positive. Default sensitivity: 7
interval:
The number of milliseconds hoverIntent waits between reading/comparing mouse coordinates. When the user's mouse first enters the element its coordinates are recorded. The soonest the "over" function can be called is after a single polling interval. Setting the polling interval higher will increase the delay before the first possible "over" call, but also increases the time to the next point of comparison. Default interval: 100
over:
Required. The function you'd like to call onMouseOver. Your function receives the same "this" and "event" objects as it would from jQuery's hover method.
timeout:
A simple delay, in milliseconds, before the "out" function is called. If the user mouses back over the element before the timeout has expired the "out" function will not be called (nor will the "over" function be called). This is primarily to protect against sloppy/human mousing trajectories that temporarily (and unintentionally) take the user off of the target element... giving them time to return. Default timeout: 0
out:
Required. The function you'd like to call onMouseOut. Your function receives the same "this" and "event" objects as it would from jQuery's hover method. Note, hoverIntent will only call the "out" function if the "over" function has been called on that same run.
The general idea is to use setTimeout
, like so:
$('.icon').hover(function() {
$('li.icon > ul').slideDown('fast');
}, function() {
setTimeout(function() {
$('li.icon > ul').slideUp('fast');
}, 2000);
});
But this may do counterintuitive things if the user mouses out and then mouses in again quickly—this doesn't account for clearing the timeout when the user hovers over it again. That would require additional state.
The following will stop the sliding from triggering by 2 seconds:
$('.icon').hover(function() {
$('li.icon > ul').delay(2000).slideDown('fast');
}, function() {
$('li.icon > ul').slideUp('fast');
});
$('.icon').on("mouseenter mouseleave","li.icon > ul",function(e){
var $this = $(this);
if (e.type === 'mouseenter') {
clearTimeout( $this.data('timeout') );
$this.slideDown('fast');
}else{ // is mouseleave:
$this.data( 'timeout', setTimeout(function(){
$this.slideUp('fast');
},2000) );
}
});
or you could simply use
transition:all 2s ease-in-out.
make sure that you add -webkit, -moz and -o for different browsers.
I think this is code your need:
jQuery( document ).ready( function($) {
var navTimers = [];
$('.icon').hover(function() {
var id = jQuery.data( this );
var $this = $( this );
navTimers[id] = setTimeout( function() {
$this.children( 'ul' ).slideDown('fast');
navTimers[id] = "";
}, 300 );
},
function () {
var id = jQuery.data( this );
if ( navTimers[id] != "" ) {
clearTimeout( navTimers[id] );
} else {
$( this ).children( "ul" ).slideUp('fast');
}
}
);
});
var timer;
var delay = 200;
$('#hoverelement').hover(function() {
on mouse hover, start a timeout
timer = setTimeout(function() {
Do your stuff here
}, delay);
}, function() {
Do mouse leaving function stuff here
clearTimeout(timer);
});
//edit: instert code
I would like to add to Paolo Bergantino that you can do this without the data attribut:
var timer;
$('.icon').hover(function() {
clearTimeout(timer);
$('li.icon > ul').slideDown('fast');
}, function() {
timer = setTimeout(function() {
$('li.icon > ul').slideUp('fast');
}, 2000);
});