Unstable Mouseenter/mouseleave Submenu
Solution 1:
This is a hover menu I ever wrote. The advantage of this is that it uses a delay for the hover to work. So if you move really quick over multiple menu items you wont get a "flashing effect". You have to hover over an element for 150ms for it to work. You can adjust this value to your liking.
It looked like your fading functions seem to cause some trouble though. Therefore i created the same effect in css and used classes to toggle which made it work a lot smoother.
How this works:
- On both mouseenter and mouseleave events the current time is saved in a global variable
lastAction
. - On both mouseenter and mouseleave events a timer will start. After
hoverdelay
in milliseconds the timer ends. - When the timer end it will check if the time saved before is still the same as in the global variable. If an other mouseenter/mouseleave event has occurred during this time the global will have a different value. If that is the case do nothing, otherwise run the code belonging to the event.
I replaced the jQuery fade functions with a css effect. The reason for this is because the fade effect is not good for fast changes between fadeIn()
and fadeOut()
. AddClass()
and removeClass()
works a lot better for this. By adding a transition effect on the opacity you get the same fadeIn/fadeOut effect.
If you want timing to be faster or slower just change the amount of seconds.
var hoverdelay = 150;
var lastAction = 0;
$(document).ready(function() {
$('#wrapper').on({
mouseenter: mouseEnterFunction,
mouseleave: mouseLeaveFunction
}, '.subMenuHoverArea');
});
function mouseEnterFunction() {
var now = (new Date().getTime());
var id = $(this).attr('id');
lastAction = now;
window.setTimeout(function() {
if (lastAction === now) {
showMenu(id);
}
}, hoverdelay);
}
function mouseLeaveFunction() {
var now = (new Date().getTime());
lastAction = now;
window.setTimeout(function() {
if (lastAction === now) {
hideMenu();
}
}, hoverdelay);
}
function showMenu(id) {
$('#subMenuContent').empty().append('<li>'+ id + '</li>').addClass('activeMenu');
}
function hideMenu() {
$('#subMenuContent').removeClass('activeMenu');
}
.subMenuJS {
background-color: yellow;
}
#subMenuContent {
background-color: pink;
}
.menu {
opacity: 0;
transition: opacity 0.5s;
}
.activeMenu {
opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id='wrapper'>
<ul>
<li><a id="menu1" href="#" class="subMenuHoverArea subMenuJS">Menu 1</a></li>
<li><a id="menu2" href="#" class="subMenuHoverArea subMenuJS">Menu 2</a></li>
<li><a id="menu3" href="#" class="subMenuHoverArea subMenuJS">Menu 3</a></li>
</ul>
<div class="subMenuSubMenu">
<div class="contentMain">
<ul id="subMenuContent" class="subMenuHoverArea menu">test</ul>
</div>
</div>
</div>
To answer your question about how efficient it is to create a date object every time. Here is a piece of code that does it 10000 times.
For me it will cost 10 till 20 ms to do it that often. I think that in worse case scenario that event happens 100 times in a second at max if the user is really spastic. Therefore I don't think performance is an issue. Never had complains about it on my site too.
var start = (new Date().getTime());
for(var i = 0; i < 10000; i++) {
var dummy = (new Date().getTime());
}
var end = (new Date().getTime());
console.log((end - start) + ' ms');
Solution 2:
You need to use jquery "hover" method.
Try this :
var menuItems1 = [
'<li><a href="#">Undermeny1 1</a></li>',
'<li><a href="#">Undermeny1 2</a></li>',
'<li><a href="#">Undermeny1 3</a></li>',
'<li><a href="#">Undermeny1 4</a></li>'
];
var inSubMenu = false;
var lastId = "";
$(document).ready(function(){
$('.subMenuHoverArea').hover(function() {
var thisid=''
console.log('mouse enter');
if ($(this).hasClass('subMenuJS')) {
thisid = $(this).attr('id');
} else {
thisid = lastId;
}
if (thisid != lastId && lastId != "") {
$('#subMenuContent').html('');
populateMenu(thisid);
$('.subMenuSubMenu').fadeIn('fast');
} else {
if (!inSubMenu) {
$('#subMenuContent').html('');
populateMenu(thisid);
$('.subMenuSubMenu').fadeIn('fast');
}
}
lastId = thisid;
inSubMenu = true;
}, function() {
console.log('mouse leave');
setTimeout(function() {
console.log('time out, and inSubMenu = ' + inSubMenu);
if (!inSubMenu) {
$('#subMenuContent').html('');
$('.subMenuSubMenu').fadeOut('fast');
}
inSubMenu = false;
}, 350);
});
});//jq
function populateMenu(menuId){
$('<li> Mouse Moved on : ' + menuId + '</li>').appendTo($('#subMenuContent'));
// Populates ul element with li from chosen array by appending it through a for loop. Not related to problem
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="parentMenu">
<li><a id="menu1" href="#" class="subMenuHoverArea subMenuJS">Menu 1</a></li>
<li><a id="menu2" href="#" class="subMenuHoverArea subMenuJS">Menu 2</a></li>
<li><a id="menu3" href="#" class="subMenuHoverArea subMenuJS">Menu 3</a></li>
</ul>
<div class="subMenuSubMenu">
<div class="contentMain">
<ul id="subMenuContent" class="subMenuHoverArea"></ul>
</div>
</div>
Post a Comment for "Unstable Mouseenter/mouseleave Submenu"