Вообще очень неочевидный код, как будто бы содержит логические ошибки
Касательно функции-обработчика click для документа (подписывается в closeDrop):
1. первый if - для упрощения восприятия стоит инвертировать условие и сделать ранний возврат
т.е. вместо
if (!drop.target.matches('.dropbtn'))
сделать
if (drop.target.matches('.dropbtn')) return;
и убрать лишние фигурные скобки
2. Т.к. насколько я понимаю, в этой функции нас интересуют исключительно открытые выпадашки - чтобы их закрыть, то мы можем выбрать сразу только открытые - заменив
let dropdowns = document.getElementsByClassName("dropdown-content");
на
let dropdowns = document.querySelectorAll(".dropdown-content.show");
3. В if в цикле по элементам происходит поиск родителя с классом
.dropdown
(вызов
.closest('.dropdown')
), т.е. самого верхнего элемента - общего родителя кнопки и самой выпадашки, но сравнивается он с одной из выпадашек (
openDropdown
, который имеет класс
.dropdown-content.show
, но не
.dropdown
), т.е это условие всегда истинно, т.к. в данной вёрстке никогда
drop.target.closest('.dropdown')
не будет равен
openDropdown
. Так же сюда же, какой смысл делать .closest от таргета клика на каждом шаге цикла, если он в течение всей функции будет одинаков?
Далее проверяется
drop.target !== openDropdown
, который будет всегда true, кроме случая клика строго по .dropdown-content.show и ни в какого его потомка
4. Опять же, если судить по HTML-коду, то выпадашка уникальна - т.к. указан id (который обязан быть уникален в документе), т.е. много таких вставлять нельзя. Но в обработчике click выпадашки как будто бы во множественном числе упоминаются. Тут нужно уже решить, как правильно должно быть - либо от id и привязки к нему избавляться, либо незачем городить перебор элементов в цикле в обработчике click
Теперь, как я бы написал решение на голом html+js:
Переименовал классы для понятности и убрал id
<div class="dropdown-wrapper">
<button class="dropdown-open-button">
<img class="dropdown-open-button-img" src="./img/yellow_mark.png" alt="mark">
Обнинск
<img class="dropdown-open-button-arrow" src="./img/drop-arrow.png" alt="arrow">
</button>
<div class="dropdown-content">
<a href="mytishchi.html">Мытищи</a>
</div>
</div>
И здесь реализовал бы скрипт иначе, отвязавшись от id, и сделав поддержку множественных выпадашек
function hydrateDropdown(wrapperEl) {
// получив элемент-обёртку, найдём внутри него кнопку и саму выпадашку
const buttonEl = wrapperEl.querySelector('button.dropdown-open-button')
const contentEl = wrapperEl.querySelector('div.dropdown-content')
function onButtonClick() {
contentEl?.classList.toggle('show')
}
// повесим на кнопку обработчик, который будет показывать/скрывать выпадашку
buttonEl?.addEventListener('click', onButtonClick)
// и реализуем простой обработчик клика по документу
function onDocumentClick(event){
// проверим, находится ли кликнутый элемент внутри именно текущей обёртки
if (event.target?.closest('.dropdown-wrapper') === wrapperEl) return // если да, то ничего не делаем
contentEl?.classList.remove('show') //если нет, то скрываем текущую выпадашку
}
document.addEventListener('click', onDocumentClick)
}
// возьмём все обёртки из документа и добавим к ним функциональность выпадашек
Array.from(document.querySelectorAll('.dropdown-wrapper')).forEach(hydrateDropdown)