Меню наведения jQuery не исчезает

EDIT: посмотрите это в действии здесь: http://jsbin.com/emobi/5 -- и это с помощью mouseenter/mouseleave.

У меня есть базовое меню, использующее несколько вложенных UL, что, я думаю, довольно стандартно. При наведении курсора на LI из «корневого» меню я хочу, чтобы отображалась UL в этом LI. Переместите мышь в другое LI, оно покажет это подменю. Переместитесь вниз к подменю, и оно останется, пока вы наводите курсор на каждый элемент. У меня он работал с простым набором jQuery.hover(), но потом я столкнулся с проблемами. Когда на странице элемент меню «root» получает класс «current-page», и если этот класс существует, я хочу, чтобы он отображал это подменю статически после отключения мыши.

Надеюсь, я объяснил это достаточно хорошо. Я просто добавил переменную в функции наведения, поэтому при отключении мыши она запускала .show() в подменю текущей страницы. Легкий. За исключением того, что когда я перемещаю мышь между отдельными LI подменю, она возвращается к подменю текущей страницы. Поэтому я попытался добавить элемент таймера на основе другого вопроса здесь. Это усугубило ситуацию — теперь подменю просто не исчезают.

Вот мой CSS, разметка и JS... как, черт возьми, мне заставить это работать правильно?

Разметка:

<div id="menu">
<div id="navbar">
    <ul id="firstmenu">
        <li>
            <a href="http://localhost/site/pageone">page one</a>
            <ul class="submenu">
                <li><a href="http://localhost/site/pageone/subone">subone</a></li>
                <li><a href="http://localhost/site/pageone/subtwo">subtwo</a></li>
                <li><a href="http://localhost/site/pageone/subthree">subthree</a></li>
                <li><a href="http://localhost/site/pageone/subfour">subfour</a></li>
                <li><a href="http://localhost/site/pageone/subfive">subfive</a></li>
            </ul>
        </li>

        <li>
            <a href="http://localhost/site/pagetwo">barely there</a>
            <ul class="submenu">
                <li><a href="http://localhost/site/pageone/subone">subone</a></li>
                <li><a href="http://localhost/site/pageone/subtwo">subtwo</a></li>
                <li><a href="http://localhost/site/pageone/subthree">subthree</a></li>
                <li><a href="http://localhost/site/pageone/subfour">subfour</a></li>
                <li><a href="http://localhost/site/pageone/subfive">subfive</a></li>
            </ul>
        </li>
        <li class="current-page">
            <a href="http://localhost/site/pagetwo">kith & kin</a>
            <ul class="submenu">
                <li><a href="http://localhost/site/pageone/subone">subone</a></li>
                <li><a href="http://localhost/site/pageone/subtwo">subtwo</a></li>
                <li><a href="http://localhost/site/pageone/subthree">subthree</a></li>
                <li><a href="http://localhost/site/pageone/subfour">subfour</a></li>
                <li><a href="http://localhost/site/pageone/subfive">subfive</a></li>
            </ul>

        </li>
        <li>
            <a href="http://localhost/site/pagethree">focal point</a>
            <ul class="submenu">
                <li><a href="http://localhost/site/pageone/subone">subone</a></li>
                <li><a href="http://localhost/site/pageone/subtwo">subtwo</a></li>
                <li><a href="http://localhost/site/pageone/subthree">subthree</a></li>
                <li><a href="http://localhost/site/pageone/subfour">subfour</a></li>
                <li><a href="http://localhost/site/pageone/subfive">subfive</a></li>
            </ul>
        </li>
        <li>
            <a href="http://localhost/site/pagefour">products</a>
            <ul class="submenu">
                <li><a href="http://localhost/site/pageone/subone">subone</a></li>
                <li><a href="http://localhost/site/pageone/subtwo">subtwo</a></li>
                <li><a href="http://localhost/site/pageone/subthree">subthree</a></li>
                <li><a href="http://localhost/site/pageone/subfour">subfour</a></li>
                <li><a href="http://localhost/site/pageone/subfive">subfive</a></li>
            </ul>
        </li>
        <li>
            <a href="http://localhost/site/pagefive">clients</a>
        </li>

    </ul>
</div></div>

А вот и CSS:

    #navbar {
     margin: 0;
     padding: 0;
     border: 0;
     text-align: center;
 }

 #firstmenu {
    margin: 6px auto 0 auto;
    font-size: 16px;
    list-style-type: none;
    letter-spacing: -1px;
 }

 #firstmenu li {
    display: inline;
    position:relative;
    overflow: hidden;
    text-align: center;
    margin-right: 10px;
    padding: 5px 15px;
 }

 #firstmenu a {
    text-decoration: none;
    outline: none;
    color: black;
    font-weight: 700;
    width: 75px;
    cursor: pointer;
 }

.current-page {
     color: white;
     background: url(../images/down_arrow.png) bottom center no-repeat;

}
.current-page a {
     color: white;
     border-bottom: 1px solid black;
}

#firstmenu .current-page a {
    color: white;
}

#firstmenu li.hover {
     color: white;
     background: url(../images/down_arrow.png) bottom center no-repeat;
}
#firstmenu li.hover a {
     color: white;
     border-bottom: 1px solid black;
}

#firstmenu li ul li.hover {
     color: white;
     background: none;
}
#firstmenu li ul li.hover a {
     color: white;
     border-bottom: none;
     text-decoration: underline;
}

#firstmenu li ul {
    width: 900px;
     color: white;
     font-size: .8em;
     margin-top: 3px;
     padding: 5px;
     position: absolute;
     display: none;
}

#firstmenu li ul li {
    list-style: none;
    display: inline;
    width: auto;
}

#firstmenu li ul li a {
    color: white;
    font-weight: normal;
    border: none;
}

.sub-current-page {
    font-weight: bold;
    text-decoration: underline;
}

#firstmenu li ul li.sub-current-page a {
    font-weight: bold;
}

И, наконец, мой не совсем рабочий JS (это, конечно, в $(document).ready()):

// Initialize some variables
    var hideSubmenuTimer = null;
    var current_page;
$('.current-page ul:first').show();

    // Prep the menu
    $('#firstmenu li').hover(function() {
        // Clear the timeout if it exists
        if(hideSubmenuTimer) { clearTimeout(hideSubmenuTimer); }

        // Check if there's a current-page class set
        if($('li.current-page').length > 0) {
            current_page = $('li.current-page');
        } else {
            current_page = false;
        }

        // If there's a current-page class, hide it
        if(current_page) { current_page.children('ul:first').hide(); }

        // Show the new submenu
        $(this).addClass('hover').children('ul:first').show();

    }, function(){
        // Just in case
        var self = this;
        // Clear the timeout if it exists
        if(hideSubmenuTimer) { clearTimeout(hideSubmenuTimer); }

        // Check if there's a current-page class set
        if($('li.current-page').length > 0) {
            current_page = $('li.current-page');
        } else {
            current_page = false;
        }

        // Set a timeout on hiding the submenu
        hideSubmenuTimer = setTimeout(function() {
            // Hide the old submenu
            $(self).removeClass('hover').children('ul').hide();

            // If there's a current-page class, show it
            if(current_page) { current_page.children('ul:first').show(); current_page.css('color', 'white'); }
        }, 500);
    });

Так что я делаю так неправильно?

В качестве примечания: я использую $('.current-page ul:first').show(), потому что, если бы я задал .current-page какой-либо параметр «отображения» в CSS, он действительно странно позиционировался на странице. страница.


person Nathan Loding    schedule 10.04.2010    source источник


Ответы (3)


Ответ заключается в том, что скрипт пытался запустить функции hover/mouseenter/все, что угодно в LI подменю. Дав каждому элементу LI корневого меню собственный класс, теперь это работает. Таким образом, он не вызывает функции в подменю LI. Вот готовая функция:

$('#firstmenu .root-item').mouseenter(function() {
    $(this).addClass('hover').children('ul:first').show();
    if($('.current-page').length > 0) {
        $('.current-page').children('ul:first').hide();
    }
}).mouseleave(function() {
    $(this).removeClass('hover').children('ul').hide();
    if($('.current-page').length > 0) {
        $('.current-page').children('ul:first').show();
    }
});
person Nathan Loding    schedule 11.04.2010

Зачем ты возишься с таймаутами? Должны ли вы просто .toggle()?

person Josh K    schedule 10.04.2010
comment
.toggle() для события клика; Я хочу, чтобы меню работало при наведении курсора мыши. - person Nathan Loding; 11.04.2010
comment
Да, вы можете .toggle() использовать класс для элемента в function(){...} из .hover(. - person Josh K; 11.04.2010

Я переписал его, чтобы использовать не наведение, а наведение и отключение мыши. Не уверен, что вам это нравится, но вот код:

$(document).ready(function(){
          $(".submenu").hide();
          $("li").mouseover(function(){
            $(this).find('.submenu').show();
            });
          $("li").mouseout(function(){
            $(this).find('.submenu').hide();
            })
});

редактировать: я нашел время, чтобы просмотреть ваш код и нашел оскорбительную строку:

#firstmenu li {
    display: inline;

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

Вероятно, вам также следует переосмыслить использование списков в качестве таблиц...

person tzenes    schedule 10.04.2010
comment
mouseover и mouseout будут запускать дочерние элементы, скрывая их... вам нужны mouseenter и mouseleave здесь. - person Nick Craver; 11.04.2010
comment
На самом деле, когда он входит в дочерний элемент, он вызывает mouseover в дочернем li, который будет просачиваться к исходному li и повторно отображать их. Хотя вы правы, mouseenter и mouseleave были бы чище - person tzenes; 11.04.2010
comment
@tzenes - событие mouseout предыдущего элемента срабатывает до mouseover следующего элемента, подумайте о том, как работают focus и blur, та же ситуация. Таким образом, дочерний элемент скрывается до того, как он mouseover будет срабатывать, но он не виден, он просто скрыт, поэтому он никогда не сработает. - person Nick Craver; 11.04.2010
comment
Это по-прежнему вызывает одну из первых проблем, с которыми я столкнулся. При горизонтальном наведении курсора на подменю меню исчезает и возвращается к меню текущих страниц при выходе из одного меню. Вот пример проблемы в действии: pastebin.com/ZTZipdGG - person Nathan Loding; 11.04.2010
comment
@Nick — попробуйте здесь: jsbin.com/ejuwe У вас возникла проблема с параллелизмом. Когда движение мыши обновляется, он смотрит, какой элемент dom закончился, затем видит, что это не тот же элемент, и mouseout добавляется в очередь событий, затем он видит, что это новый элемент, и добавляет mouseover в очередь событий. Поскольку он сэмплирует элемент dom в начале функции, он все еще думает о дочернем элементе li, даже если он удаляется. - person tzenes; 11.04.2010
comment
@tzenes - что значит переосмыслить использование списков в качестве таблиц? Мне удалось решить проблему (см. мой опубликованный ответ), не меняя стиль display: inline. Я не думаю, что он удаляет его из дочернего элемента элемента списка. Могу ошибаться, я не эксперт по DOM. - person Nathan Loding; 11.04.2010