In a 3-level menu, how to set a time when the event is mouseout in the second level to the third?

5

I have a menu with 3 vertical levels (similar to globo.com), my problem is when I I am in the last item of the 2nd level (for example) and move the mouse to the 1st item of the 3rd level, the Hover event on 2nd level is activated and I lose the navigation that can not reach the 3rd level.

I need a solution similar to the one on the globe, when I'm in 2nd level and I'm going to the 3rd, I need to set a time for it to reach 3rd level.

My current script looks like this:

//manipula primeiro e segundo nivel
    $("#main-menu ul > li.mn-item-li").mouseenter(function (e) {
        var currentMenu = $(this);

        if (currentMenu.hasClass('sub-menu')) {
            currentMenu.find('.mn-item-a').addClass('active');
        }

        currentMenu.children('div').stop().show();

        //seta item do menu mais-visto aberto como padrão            
        currentMenu.find('.second-nivel').find('li').eq(0).find('a').addClass('active');
        $(".mn-maisvistos").css({ "visibility": "visible", "opacity": "1" });

        //seta altura do subnivel
        var heightSubnivel = currentMenu.find('.second-nivel').height();
        var widthtSubnivel = currentMenu.find('.second-nivel').width();
        currentMenu.find('.second-nivel').css({ 'height': heightSubnivel + 'px' });
        currentMenu.find('.third-nivel').css({ 'height': heightSubnivel + 'px' });

        //manipula segundo e terceiro nivel
        var timer;
        var teste = function () {

            currentMenu.find('.second-nivel > li a').mouseenter(function () {
                var dataSubNivel = $(this).data("menu-id");
                var indexSubNivel = $(this).parent().index();

                $('.second-nivel > li a').removeClass('active');

                if ($(this).parent().hasClass("subnivel")) {

                    //console.info(indexSubNivel)

                    $('.third-nivel > li').css('visibility', 'hidden');
                    $(this).parents('.second-nivel').next().find("." + dataSubNivel).css({ 'visibility': 'visible', 'opacity': '1' });
                    $(this).addClass('active');

                } else {

                    $('.third-nivel > li').css('visibility', 'hidden');
                    $(this).css("background-image", "none");
                }
                clearTimeout(timer);
            })
        }

        currentMenu.find('.second-nivel > li a').mouseleave(function () {
            $(this).off('mouseenter');
            timer = setTimeout(function () { teste() }, 500);
        });

        currentMenu.find('.second-nivel > li a').mousemove(function (event) {
            var pageCoords = "( " + event.pageX + ", " + event.pageY + " )";
            var clientCoords = "( " + event.clientX + ", " + event.clientY + " )";
            console.info("( event.pageX, event.pageY ) : " + pageCoords);               
        });

    }).mouseleave(function () {
        $(this).find('.third-nivel > li').css({ 'visibility': 'hidden', 'opacity': '0' });
        $(this).find('.second-nivel li a').removeClass('active');
        $(this).children("div").stop().hide();
        $(this).find('.mn-item-a').removeClass('active');
    });
    
asked by anonymous 04.02.2014 / 19:28

3 answers

1

Instead of creating a menu by yourself - and because you're already using jQuery - you'd rather use a plugin that already does it for you:

Plugins are usually tested, have mechanisms to prevent such problems, and include features such as mobile device support.

There is the plugin for Bootstrap 2 , which uses your one-time idea, and the jQuery-menu-aim that uses another strategy to avoid this problem.

    
04.02.2014 / 23:27
1

Instead of using .css() you could use .animate() , so you could control how long the animation would take to happen.

currentMenu.find('.second-nivel').animate({ height: heightSubnivel }, 500);
currentMenu.find('.third-nivel').animate({ height: heightSubnivel }, 500);

Besides being able to control the animation that each item will do to open and close, you can still control the time it will take. Any questions at documentation .

    
07.02.2014 / 20:43
0

It would be nice to see HTML relevant to your problem to understand why, for example, you thought it necessary to "set the height of the sub-level". But, quite generally, the type of menu you want to do does not require jQuery.

Using only pseudoclasse hover of CSS, you can create a menu of three levels similar to that of Globo.com. I made a very simple example, I did not bother to make it look beautiful, but I hope the idea is clear: link

The trick was to use position: absolute to let one DIV appear on top of the other "naturally". Using the ativo class allows one of the DIVs to already open along with the second level of the menu. It is not ideal and does not work in all cases, but I left it in the name of simplicity.

    
05.02.2014 / 01:22