Dejo Dekic Dejo Dekic - 6 months ago 9
Javascript Question

How to create a smooth animation for my menu?

I have a menu that expands "on hover" but the problem is that if I hover over an item , and that item is running an animation the next item animation will not be smooth (basically sub-menu will show up in the middle of animation).

I have created a JS Fiddle of the problem.

I think that this part of my code is causing the issue:

j('.active').next('ul')
.removeClass('sub-menu')
.addClass('jsub-menu').css({
'visibility':'',
'opacity':'',
'height':get_height_of_first_child +'px',
'width':'0'
});
j('.active').next('.jsub-menu').animate({width:get_width},2000);

j('.active').next('.jsub-menu').animate({height:get_submenu_height},2000);


Edit: Here is the updated Fiddle Code. If you look closely on line
59
I have added this code

if(j('.active').next('.jsub-menu').is(':animated')){
j('.active').next('.jsub-menu').hide();
}


Now if you hover over an "Hover me while I am expanding!" and that menu is animated it will hide the menu (don't want that but bear with me).

So now try to hover over an "Hover me" only and WAIT 4-5 seconds and THEN hover over "Hover me while I am expanding!" you will see that next menu animates smoothly.

This is the effect I want but obviously I do not want to hide the menu in the process.

Answer

Here is how I would do it. It checks to see if it is the direct sub menu of the parent .jnav and uses slideDown if so. Otherwise it gets the width (while the element has visibility:hidden) and animates it to that width after

var j = jQuery.noConflict();    
j(document).ready(function () {    
    j('ul.nav').removeClass('nav').addClass('jnav');    
    j('ul.jnav li').hover(function () {
        if (j(this).children('ul:first').hasClass('jsub-menu')) { 
            return false; 
        } else {    
            if(j('ul.jnav > li').is(this)) {
                j(this).find('ul.sub-menu:first').not(':animated').slideDown(500);
            } else {
                var elem = j(this).find('ul.sub-menu:first').not(':animated');
                elem.css({
                    visibility: 'hidden',
                    display: 'block'                    
                });
                var elemWidth = elem.width();
                console.log(elemWidth);
                elem.css({
                    width: '0px',
                    visibility: 'visible'
                }).animate({
                    width: elemWidth
                });
            }
        }
    }, function () {
        j(this).find('ul:first').slideUp(500, function () {
            j(this).removeClass('jsub-menu').addClass('sub-menu');            
        });
    });    
});

Updated jsFiddle

Comments