#javascript
#javascript
Вопрос:
Я пытался создать очень простое выпадающее меню, но не могу правильно скрыть часть внешнего щелчка. Я прошел несколько итераций, но всегда оказываюсь неспособным правильно отклонить его или закрыть другие открытые выпадающие списки, когда активирован другой. Вот мой последний вариант.
function Menu(trigger) {
let expanded = trigger.getAttribute("aria-expanded") === "true" || false;
let menu = trigger.nextElementSibling;
trigger.setAttribute("aria-expanded", !expanded);
menu.hidden = !menu.hidden;
}
const menuTriggers = document.querySelectorAll(".menu-trigger");
menuTriggers.forEach((menuTrigger) => {
menuTrigger.addEventListener("click", () => {
Menu(menuTrigger);
});
});
<button class="menu-trigger" aria-expanded="false">Menu</button>
<ul class="menu" hidden>
<li class="menu-item">
<a class="menu-link" href="">Books</a>
</li>
<li class="menu-item">
<a class="menu-link" href="">Authors</a>
</li>
<li class="menu-item">
<a class="menu-link menu-link-separator" href="">Genres</a>
</li>
<li class="menu-item">
<a class="menu-link" href="">Themes</a>
</li>
</ul>
Ответ №1:
Вам нужно будет прослушать событие наведения курсора мыши на объект window, чтобы обнаружить щелчок и закрыть выпадающее меню, только если event.target не содержится в самом выпадающем меню.
function Menu(trigger)
{
let expanded = trigger.getAttribute("aria-expanded") === "true" || false;
let menu = trigger.nextElementSibling;
trigger.setAttribute("aria-expanded", !expanded);
menu.hidden = !menu.hidden;
if(!menu.hidden)
{
setTimeout(() =>
{
let eventType = "mousedown";
let handler = (e) =>
{
if (trigger !== e.target amp;amp; !menu.contains(e.target))
{
Menu(trigger);
}
window.removeEventListener(eventType, handler, false);
};
window.addEventListener(eventType, handler, false);
}, 0);
}
}
const menuTriggers = document.querySelectorAll(".menu-trigger");
menuTriggers.forEach((menuTrigger) =>
{
menuTrigger.addEventListener("click", () =>
{
Menu(menuTrigger);
});
});
<div style="display:inline-block">
<button class="menu-trigger" aria-expanded="false">Menu</button>
<ul class="menu" hidden>
<li class="menu-item">
<a class="menu-link" href="https://amazon.com">Books</a>
</li>
<li class="menu-item">
<a class="menu-link" href="">Authors</a>
</li>
<li class="menu-item">
<a class="menu-link menu-link-separator" href="">Genres</a>
</li>
<li class="menu-item">
<a class="menu-link" href="">Themes</a>
</li>
</ul>
</div>
Комментарии:
1. Спасибо за ваш ответ. Я попытаюсь обработать внешний щелчок внутри
Menu()
функции, чтобы установить более четкое определение компонента.2. Нет проблем, я отредактировал ответ, переместив код в
Menu()
функцию.3. Попробовал прямо сейчас. Спасибо за советы! Из того, что я мог собрать
setTimeout()
, это не обязательно; это правильно? И еще одно условие должно быть добавлено как частьhandler()
, чтобы разрешить переход по ссылкам :!trigger.contains(e.target) amp;amp; !menu.contains(e.target)
.4. Вы можете обнаружить, что в некоторых ситуациях setTimeout необходим. Это предотвращает нажатие кнопки от запуска события mousedown во время того же щелчка. Странно, но я видел, как это происходит в некоторых браузерах.
ul
Элемент представляет собой блочный элемент, который незаметно охватывает всю ширину экрана. Чтобы решить эту проблему, я обернул html внутриinline-block
. Вы разберетесь в деталях; для вас это было только начало.5. Еще раз спасибо за помощь. Действительно, кажется, что необходимо предотвратить запуск нескольких событий, либо хотя
setTimeout()
, либо различными условными операторами.