Сложности со скользящим меню jQuery

Я пытаюсь создать многослойное меню с классными эффектами скольжения/затухания. Прямо сейчас он работает с моего первого щелчка, но после этого он терпит неудачу.

HTML

<ul id="menu">
<li>
    Development
    <div>
        <ul>
            <li>Sub 1</li>
            <li>Sub 2</li>
        </ul>
    </div>
</li>
<li>
    Story
    <div>
        <ul>
            <li>Sub 1</li>
            <li>Sub 2</li>
        </ul>
    </div>
</li>
<li>
    News
    <div>
        <ul>
            <li>Sub 1</li>
            <li>Sub 2</li>
        </ul>
    </div>
</li>
</ul>​

JavaScript

var observeClicks = function(){
    var lis = $('#menu').children('li');

    lis.click(function(){
        lis.unbind();
        var $this = $(this);
        var $div = $($this.children('div')[0]);
        var $ul = $($div.children('ul')[0]);

        var clone = $ul.clone(true, true)
            .css({visibility: 'hidden', display: 'block'});
        clone.attr('style', clone.attr('style').replace('block', 'block !important'))
            .insertAfter($ul);

        setTimeout(function(){
            $ul.css({height: clone.css('height')});
            $div.css({height: clone.css('height')});
            clone.remove();
        }, 0);

        if(!lis.hasClass('current')){
            $this.addClass('current');
            $div.slideDown(350, function(){
                $ul.fadeIn(350);
                observeClicks();
            });
        }else{
            if(!$this.hasClass('current')){
                $current = $($('.current')[0]);
                $cdiv = $($current.children('div')[0]);
                $cul = $($cdiv.children('ul')[0]);

                $cdiv.css({height: $cul.css('height')});

                $this.addClass('current');
                $current.removeClass('current');
                $cul.fadeOut(350, function(){
                    $cdiv.slideUp(350, function(){
                        $div.slideDown(350, function(){
                            $ul.fadeIn(350);
                            observeClicks();
                        });
                    });
                });
            }else{
                observeClicks();
            }
        }
    });
}
observeClicks();

CSS

#menu {
    cursor: pointer;
    width: 150px;
}

#menu div {
    display: none;
    width: 100%;
}

#menu li ul {
    display: none;
    margin-left: 25px;
}

Первая интересная проблема, с которой я столкнулся, заключалась в том, что вместо скольжения мое меню просто «всплывало». Это было потому, что div не занимал места, пока не отображались элементы внутри него. Поэтому я преодолел это, задав ему фиксированную область. (Ширина задается в CSS, а высота задается в JavaScript). Я думаю, что проблема может заключаться в этом, я вставляю фиктивный элемент, читаю его высоту, назначаю это div, а затем удаляю элемент. Это схематично, я знаю, но я не мог найти лучшего способа.

В любом случае, когда я впервые нажимаю на пункт меню, он работает отлично. Но как только я пробую свой второй щелчок, кажется, что высота для div не устанавливается, и эффекта скольжения нет. Посмотрите здесь.

Вы также можете заметить, что вместо того, чтобы пытаться возиться с .stop() для анимации, я просто отвязываю обработчик кликов, а затем повторно привязываю их после завершения всех анимаций. Это было преднамеренно, и у меня была эта проблема, прежде чем добавить это. Если бы кто-нибудь мог показать мне, что исправить, я был бы очень признателен.


person Aust    schedule 25.10.2012    source источник
comment
Я сделал это некоторое время назад. Может быть полезно, если вам нужно меньше кода для аналогичного меню: jsfiddle.net/aCaEG   -  person Johan    schedule 25.10.2012


Ответы (2)


Похоже, что проблема в фрагменте кода с высотой клона. Я не уверен, почему он работает только с первым нажатым элементом, но вы можете исправить это, просто установив высоту этих элементов в css:

#menu div {
    display: none;
    width: 100%;
    height: 40px;
}

#menu li ul {
    display: none;
    margin-left: 25px;
    height: 40px;
}

И удаляя код js, который клонирует и назначает высоты, он выглядит нормально в jsfiddle: http://jsfiddle.net/j7EHu/< /а>

person Community    schedule 25.10.2012
comment
Я полагаю, что мог бы сделать это таким образом, но я надеялся найти автоматический способ получения высоты, поэтому, когда я добавляю/удаляю что-то из своего меню, мне не нужно беспокоиться о настройке CSS снова и снова. - person Aust; 25.10.2012
comment
Вы можете просто назначить высоту компонентам с помощью простой операции, зависящей от высоты строки: $div.css({height: $ul.children().lenght*$ul.css('lineHeight')}); Вам не нужны клонирование и таймер, которые намного сложнее. - person Juanmi Rodriguez; 25.10.2012

Пожалуйста, используйте это вместо вашего кода:

#menu {
    cursor: pointer;
    width: 150px;
}

#menu div {
    display: none;
    width: 100%;
}

#menu li ul {
    margin-left: 25px;
}

JS

 $("#menu > li").click(function(){
      $('#menu .active').slideUp(350).removeClass('active');
      $(this).find('div').slideDown(350,function() {
          $(this).addClass('active');
      });
 });

Вот демо: http://jsfiddle.net/yL944/12/

person Mihai Matei    schedule 25.10.2012
comment
Я пытаюсь добиться эффекта соскальзывания вниз, а затем постепенного появления, а не просто соскальзывания вниз. - person Aust; 25.10.2012