Я не хочу доверять себе ответ, но после ответа Голды мне пришлось провести гораздо больше исследований, прежде чем я получил что-то, что сработало бы для меня, и мое решение могло бы быть полезным для других, кто прочитает это позже.Мое настоящее меню содержит несколько элементов всех типов, и даже вся разметка навигационного меню дублируется, поэтому я не могу использовать идентификаторы.Кроме общего вывода о том, что необходимо будет заменить функциональность псевдоэлемента CSS hover
на JS, я не стал использовать код Голды.
Вещи, которые я узнал:
mouseenter
и mouseleave
- лучшие события для этого, чем mouseover
и mouseout
, потому что mouseover
и mouseout
продолжают стрелять в горячем беспорядке, когда мышь перемещается между элементами в подменю (и даже иногдане стреляет, если я двигаюсь слишком быстро!).[Ответ Голды работал с mouseover/mouseout
до тех пор, пока они были пойманы на двух элементах в подменю и идентификаторы были назначены для всего.Я часами пытался найти правильные селекторы jQuery, которые бы делали то же самое с иерархией и классами DOM, но безрезультатно.] - Отличное объяснение различия между
mouseover/mouseout
и mouseenter/mouseleave
находится по адресу: https://javascript.info/mousemove-mouseover-mouseout-mouseenter-mouseleave - Я узнал о необязательном втором аргументе для селекторов jQuery: context.
$("ul",this)
означает ul
потомка (ей) $(this)
, который отлично сработал для этого.
Таким образом, решение состоит в том, чтобы подняться на уровень до <li>
родителя подменюи поймать mouseenter
и mouseleave
там.Это приводит к гораздо меньшей специальной разметке, поэтому будущие модификации структуры меню с меньшей вероятностью будут иметь ошибки из-за неуместного класса или двух.Единственный дополнительный класс, который мне был нужен, был class="hassub"
на вершине <li>
.На самом деле, я даже не ссылаюсь на класс «nav-sub» в jQuery - он мне все еще нужен только для CSS.Первоначально я думал, что применил бы jQuery только к подменю, содержащим ссылки AJAX (потому что CSS hover
работал без него), но проще позволить jQuery работать со всеми подменю, поэтому CSS ul.nav li:hover ul { display: block; }
больше не нужен,Вот код с расширенной разметкой, которая будет немного более реалистичной:
$(function() {
$(".hassub").mouseenter(function() { $("ul",this).show(); });
$(".hassub").mouseleave(function() { $("ul",this).hide(); });
$('.ajaxlink').click(function() { $(this).closest('ul').hide(); });
});
ul.nav {
background-color:rgb(88,57,7);
list-style-type: none;
text-align: center;
vertical-align: middle;
min-height: 30px;
position:sticky;
top:0;
}
ul.nav li {
display: inline-block;
position: relative;
}
ul.nav-sub {
display: none;
position: absolute;
background-color:rgb(88,57,7);
margin: -4px 0 0 15px;
border: 1px solid LightSteelBlue;
padding: 0;
border-radius: 0;
text-align: left;
min-height: 0;
z-index:100;
}
ul.nav-sub li {
display: block;
}
ul.nav a {
display: block;
color: LightSteelBlue;
padding: 10px 15px;
margin: 0;
font-family: arial, helvetica, sans-serif;
font-weight: bold;
text-decoration: none;
white-space:nowrap;
}
ul.nav a:hover {
background-color: rgb(132,78,12);
color: White;
}
/*ul.nav li:hover ul {
display: block;
}*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<ul class="nav">
<li><a href="file1.php">solo page</a></li>
<li class="hassub">
<a href="#">submenu1 (mixed) ▼</a>
<ul class="nav-sub">
<li><a href="file2.php">page 1a</a></li>
<li><a href="file3.php">page 1b</a></li>
<li><a class="ajaxlink" href="#">ajax 1-1</a></li>
<li><a href="file2.php">page 1c</a></li>
<li><a href="file3.php">page 1d</a></li>
</ul>
</li>
<li class="hassub">
<a href="#">submenu2 (only pages) ▼</a>
<ul class="nav-sub">
<li><a href="file2.php">page 2a</a></li>
<li><a href="file3.php">page 2b</a></li>
</ul>
</li>
<li id="hassub3" class="hassub">
<a href="#">submenu3 (only ajax) ▼</a>
<ul id="sub3" class="nav-sub">
<li><a class="ajaxlink" href="#">ajax 3-1</a></li>
<li><a class="ajaxlink" href="#">ajax 3-2</a></li>
</ul>
</li>
</ul>