简体   繁体   中英

Menu with mouseenter & mouseleave events

Introduction:
Hello everyone. I am trying to do a menu, but i have problem with mouseenter/mouseleave events.

What i have so far:

$("#icon").click(function() {
    $("#invis").css("display", "block");
    $("#icon").bind("mouseleave", function(){
        $("#invis").css('display', "none");
    }).bind("mouseenter", function(){
        $("#invis").css('display', "block"); 
    });
    $("#invis").bind("mouseleave", function(){
        $("#invis").css('display', "none");
    }).bind("mouseenter", function(){
        $("#invis").css('display', "block");
    });
});​  

So far, i tried this. My point is to click on the "icon", and this click would show a menu/another, hidden element. Now i want to keep it open as long, as someone keeps mouse over "icon" or actual menu. But with code i provided, once i leave my mouse and then enter again on "icon", it still keeps onmouseenter event, and menu will appear again. I know i could unbind onmouseenter event, but then once i drive off menu, onto icon, my menu would get closed, and i don't want that.

Simplest example i could think of: http://jsfiddle.net/tzzqM/5/

Question
How to make "menu" open on click event, and then keep it open as long as someone keeps mouse over menu or "icon" (both of them). Once mouse leaves area of both, menu closes, and to open it i need to click once more on "icon". Is there a another way to do this?

On mouse leaving the object, check if the mouse is still either on the menu or on the menu-button, if not, hide the menu. Basically, you're binding the event mouseleave to both elements and then checking the length of the selection. If it's 1, you're either on the menu or the button, this makes the exiting the menu button into the menu itself, not trigger the "hidding" part of the code, if the selection length is 0, then we are not over any of those elements and we hide it.

$("#icon").click(function() {
    $("#invis").css("display", "block");
        $("#invis,#icon").bind("mouseleave", function(){
            if($("#invis:hover,#icon:hover").length === 0){
                $("#invis").css('display', "none");
            }
        })
});​

There's a fiddle here .

Or the way I would write it if I had to start from scratch (just the jQuery part), since remember that you'd be jumping into the DOM pool less times and should be a little bit more efficient, although it's as functional as the first one. Here's the fiddle

var icon = $("#icon"),
    menu = $("#invis");

icon.click(function() {
    menu.show();
        $.merge(icon,menu).bind("mouseleave", function(){
            if($("#icon:hover,#invis:hover").length < 1) menu.hide();
        });
});​

Or using the suggestion from jhummel we can access the id of the new view that has the hover, and check if it's one of the two that we want to monitor. This is great because it prevents us from jumping into the pool once more, this gives us a marginal performance boost, here's the fiddle .

var icon = $("#icon"),
    menu = $("#invis");

icon.click(function() {
    menu.show();
        $.merge(icon,menu).bind("mouseleave", function(e){
            if($.inArray(e.relatedTarget.id, ["icon","invis"]) === -1){
                   menu.hide();
            }
        });
});​


Related docs:

When you use mouseover or mouseleave events, the event object in jQuery will have a relatedTarget property. You can check that property to see if the mouse is entering the other element.

$("#icon").on('click',function() {
  $("#invis").show();
}).on('mouseleave', function(e) {
  if(e.relatedTarget.id != 'invis') $('#invis').hide();    
});

$('#invis').on('mouseleave', function(e) {
  if(e.relatedTarget.id != 'icon') $(this).hide();
});

jquery relatedTarget docs

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM