Reputation: 201
I have the following website set up [site location edited] (it is just getting started, so only the top button and first level menu works):
When you hover over the "Request It" button, a "Request It menu" pops out.
I need to figure out two things:
Here is the jQuery I'm using so far:
$(document).ready(function(){
$('request-it-menu').hide();
$('#request-it-button, #request-it-menu').mouseenter(function() {
$('#request-it-menu').show();
$('#request-it-button, #request-it-menu').mouseleave(function() {
$('request-it-menu').hide();
});
});
});
Upvotes: 1
Views: 4298
Reputation: 973
I have done tons of research on this topic in the last few weeks. I could not find a satisfactory answer to this issue after reading many posts. So I decided to get my hands dirty.
Here is a utility script I wrote for hiding menu when mouse out:
util.watchMouseOut=function(id,cb){
this.shown=true;
this.statecheck={};
$(id).children().mouseout(function() {
shown=false;
dostatecheck();
}).mouseover(function() {
shown=true;
dostatecheck();
});
this.dostatecheck=function(){
try{
setTimeout(function(){
try{
clearTimeout(this.statecheck);
}catch(e){}
},5);
}catch(e){}
this.statecheck=setTimeout(function(){
if(!shown)
{
cb();
}
},20);
};
}
The idea is that mouseover and mouseout events are able to detect mouse leave, but they are also having issues with mouse crossing from one menu item to next item. That will also trigger hide menu calls. I set a variable 'shown' to true when mouse hover and false when mouseout. They will flip twice when you move across items. Then after 20ms delay, check that the final shown variable value to ensure the hide event is valid.
When you use this code, call it like this:
var watch=new util.watchMouseOut('#menuid',function(){
hidemenu();
});
You will need to implement hidemenu() function elsewhere.
Upvotes: 0
Reputation: 22570
Ok, here we go. First of all, in order to make the "sub-menu"s easier to hide, I added a class to each sub menu. This gives one focal point to call, not only in CSS, but for jquery assignments as well.
<div id="request-it-menu" class="sub-menu">
In the css, I did not much special here except to give sub-menu's a hidden display and a position of relative. Now you can redesign how you like, I gave relative position here so that the sub menu's could be positioned using top
.
.sub-menu { display: none; position: relative; }
With that all out of the way we get to the JavaScript ... almost! One more thing! In you're menu HTML, I added a data variable to each image. I used this variable to hold the ID
of each .sub-menu
. Now this isn't necessary, after all, you could make a complex statement to use strip the word button from the image id's and change it to menu, but why get complex?
<img id="request-it-button" data-submenu="#request-it-menu"
Finally! The JavaScript. It's REALLY easy at this point to make the calls both "dynamic" and "singular" thanks to our data variable. First I use a delegate version of jQuery's .on() method in order to make the mouse events add to even dynamic elements of the given selector. The selector itself is a "Blanket" statement, meaning it grabs everything fitting it's very simple description. In this case, I simply use the head menu ID straight to the img's inside.
$(function() { // same as $(document).ready(function() { ...
// calling this way in jquery is using "delegate" form of .on
// this assures function to even dynamic elements of the fitting selector
$(document).on("mouseenter", "#topMenu > img", function(e) {
var menu = $(this).data("submenu");
// position part here is temporary till you decide how you want css to arange sub menu's
$(menu).css("top", $(this).position().top-9).show();
})
.on("mouseleave", "#topMenu > img", function(e) {
var menu = $(this).data("submenu");
$(menu).hide();
})
})
$(function() {
var tmrSubMenu;
$(document).on("mouseenter", "#topMenu > img", function(e) {
$(".sub-menu").hide();
var menu = $(this).data("submenu");
$(menu).css("top", $(this).position().top-9).show();
})
.on("mouseleave", "#topMenu > img", function(e) {
var menu = $(this).data("submenu");
tmrSubMenu = setTimeout(function() { $(menu).hide(); }, 100);
})
.on("mouseenter", ".sub-menu", function(e) {
clearTimeout(tmrSubMenu);
})
.on("mouseleave", ".sub-menu", function(e) {
$(this).hide();
})
})
Upvotes: 5
Reputation: 465
$('.has-hover').hover(
function () { $('#request-it-menu').addClass("show"); },
function () { $('#request-it-menu').removeClass("show"); }
);
And CSS. Remake your styles and remove !important
:)
.show {
display: block !important;
}
Here is fiddle: http://jsfiddle.net/tAx6N/
Try to remove space between menu and submenu to prevent hover-effect interruption.
Upvotes: 0
Reputation: 1434
There is a typo in your jquery selector in line 6 - it should be $("#request-it-menu").hide()
(notice the #
). Other than that, your code is perfect.
Here is the corrected snippet that works:
$(document).ready(function(){
$('request-it-menu').hide();
$('#request-it-button, #request-it-menu').mouseenter(function() {
$('#request-it-menu').show();
$('#request-it-button, #request-it-menu').mouseleave(function() {
$('#request-it-menu').hide();
});
});
})
Upvotes: 1
Reputation: 6207
$(document).ready(function(){
$('#request-it-menu').hide();
$('#request-it-button, #request-it-menu').hover(function() {
$('#request-it-menu').toggle();
});
});
Upvotes: 0
Reputation: 1334
with this you normally will be done for all your next side menu
html :
<img id="request-it-button" src="request-it.png" alt="request-it" width="220" height="50" data="request-it" class="menu-button">
<img id="repair-it-button" src="repair-it.png" alt="repair-it" width="220" height="50" data="repair-it" class="menu-button">
...
<div id="request-it-menu" style="display: block;" class="request-it menu-context">
...
</div>
<div id="repair-it-menu" style="display: block;" class="repair-it menu-context">
...
</div>
...
js
$(document).ready(function(){
//hide all sub menu with the class menu-context
$('.menu-context').hide();
//for each element having the class menu-button
$('.menu-button').hover(
function() { //mouseenter
//find the matching menu designated by the data attribute
var desig = $(this).prop("data");
$('.'+desig).show();
},
function() { //mouseleave
//find the matching menu designated by the data attribute
var desig = $(this).prop("data");
$('.'+desig).hide();
}
);
})
Upvotes: 1