Выпадающее Меню Vanilla Javascript Toggle
Мой мозг проверился на выходные...
Я ищу решение в обычном Javascript, где, если одно выпадающее меню открывается по щелчку другого пункта главного меню, предыдущее открытое выпадающее меню будет закрыто, а затем отобразится раскрывающееся меню вновь нажатого пункта главного меню. Я знаю, что это, вероятно, так просто, но я не могу придумать решение, которое не было бы запутанным.
Также если щелкнуть вне пунктов меню (в любом месте документа, которое не является пунктом меню или выпадающий список) должен закрывать все открытые выпадающие списки.
Спасибо за любую помощь.
function testFunc(el) {
var parent = el.parentElement;
var dd = parent.lastChild.previousSibling;
dd.classList.toggle('show');
}ul { list-style: none; margin: 0; padding: 0; }
ul li {
width: 100px;
float: left;
background: #dbdbdb;
line-height: 2em;
text-align: center;
margin: 0 5px;
cursor: pointer;
}
ul li span {
display: block;
}
ul li ul {
display: none;
}
.show {
display: block;
}<ul>
<li>
<span onclick="testFunc(this)">Item 1</span>
<ul>
<li>Sub Item 1</li>
<li>Sub Item 2</li>
</ul>
</li>
<li>
<span onclick="testFunc(this)">Item 2</span>
<ul>
<li>Sub Item 1</li>
<li>Sub Item 2</li>
</ul>
</li>
<li>
<span onclick="testFunc(this)">Item 3</span>
<ul>
<li>Sub Item 1</li>
<li>Sub Item 2</li>
</ul>
</li>
<li>
<span onclick="testFunc(this)">Item 4</span>
<ul>
<li>Sub Item 1</li>
<li>Sub Item 2</li>
</ul>
</li>
</ul> 1 ответ:
Переключение видимости меню
Вы можете сохранить последнее открытое меню в переменной
openedвне функции. Затем при нажатии на меню, еслиopenedне являетсяnull, он переключитopened(т. е. скроет последнее открытое меню) и переключит выбранный пункт.let opened = null function testFunc(el) { // gets the <ul> element of the clicked menu item const menu = el.parentElement.lastChild.previousSibling; if (!opened) { // no menu item is shown opened = menu opened.classList.toggle('show'); } else if (menu == opened) { // the clicked item is already showing menu.classList.toggle('show') opened = null } else { // the clicked item is hiddden but another one is showing opened.classList.toggle('show') opened = menu opened.classList.toggle('show') } }Вот код:
let opened = null function testFunc(el) { const menu = el.parentElement.lastChild.previousSibling; if(!opened) { opened = menu opened.classList.toggle('show'); } else if(menu == opened) { menu.classList.toggle('show') opened = null } else { opened.classList.toggle('show') opened = menu opened.classList.toggle('show') } }ul { list-style: none; margin: 0; padding: 0; } ul li { width: 100px; float: left; background: #dbdbdb; line-height: 2em; text-align: center; margin: 0 5px; cursor: pointer; } ul li span { display: block; } ul li ul { display: none; } .show { display: block; }<ul> <li> <span onclick="testFunc(this)">Item 1</span> <ul> <li>Sub Item 1</li> <li>Sub Item 2</li> </ul> </li> <li> <span onclick="testFunc(this)">Item 2</span> <ul> <li>Sub Item 1</li> <li>Sub Item 2</li> </ul> </li> <li> <span onclick="testFunc(this)">Item 3</span> <ul> <li>Sub Item 1</li> <li>Sub Item 2</li> </ul> </li> <li> <span onclick="testFunc(this)">Item 4</span> <ul> <li>Sub Item 1</li> <li>Sub Item 2</li> </ul> </li> </ul>
Вариант с синтаксисом ES6
Вот вариант с некоторым синтаксисом ES6, обратите внимание, что я изменил структуру именования HTML на лучше поддерживать код, вызывая элементы по имени класса позволяет
Чтобы не пришлось использовать встроенные прослушиватели событий
Вызовите все пункты меню в одной строке
Вот код JavaScript:
let opened = null const toggleVisibility = e => e.classList.toggle('show') const toggleDropDown = e => { const clickedItem = e.target.parentElement.lastChild.previousSibling toggleVisibility(clickedItem); if (!opened) { opened = clickedItem } else if (opened == clickedItem) { opened = null } else { toggleVisibility(opened); opened = clickedItem } } [...document.querySelectorAll('.dropDown')].forEach(dropDown => dropDown.addEventListener('click', toggleDropDown))
let opened = null const toggleVisibility = e => e.classList.toggle('show') const toggleDropDown = e => { const clickedItem = e.target.parentElement.lastChild.previousSibling toggleVisibility(clickedItem); if (!opened) { opened = clickedItem } else if (opened == clickedItem) { opened = null } else { toggleVisibility(opened); opened = clickedItem } } [...document.querySelectorAll('.dropDown')].forEach(dropDown => dropDown.addEventListener('click', toggleDropDown))ul { list-style: none; margin: 0; padding: 0; } ul li { width: 100px; float: left; background: #dbdbdb; line-height: 2em; text-align: center; margin: 0 5px; cursor: pointer; } ul li span { display: block; } ul li ul { display: none; } .show { display: block; }<ul> <li> <span class="dropDown">Item 1</span> <ul> <li>Sub Item 1</li> <li>Sub Item 2</li> </ul> </li> <li> <span class="dropDown">Item 2</span> <ul> <li>Sub Item 1</li> <li>Sub Item 2</li> </ul> </li> <li> <span class="dropDown">Item 3</span> <ul> <li>Sub Item 1</li> <li>Sub Item 2</li> </ul> </li> <li> <span class="dropDown">Item 4</span> <ul> <li>Sub Item 1</li> <li>Sub Item 2</li> </ul> </li> </ul>
Переключение видимости меню + закрытие при нажатии в другом месте
Если вы хотите закрыть любое открытое меню, если пользователь нажимает за пределами меню, вам нужно будет иметь прослушиватель событий в самом документе. Таким образом, вместо того, чтобы иметь один прослушиватель событий на кнопку меню, у вас будет один, наблюдающий за любым щелчком мыши, происходящим в документе.
Прослушиватель событий определит, является ли нажатый элемент кнопкой Меню, в этом случае он запустит обработчик меню. В противном случае он закроет последний открытый пункт меню.
Код JavaScript:
let opened = null const toggleVisibility = e => e.classList.toggle('show') const handleDropdown = e => { const clickedItem = e.parentElement.lastChild.previousSibling toggleVisibility(clickedItem) if (!opened) { opened = clickedItem } else if (opened == clickedItem) { opened = null } else { toggleVisibility(opened) opened = clickedItem } } const handleClick = e => { if (e.target.className.includes('dropDown')) { handleDropdown(e.target) } else if (opened) { toggleVisibility(opened) opened = null } } document.addEventListener('click', handleClick)Вот полный код:
let opened = null const toggleVisibility = e => e.classList.toggle('show') const handleDropdown = e => { const clickedItem = e.parentElement.lastChild.previousSibling toggleVisibility(clickedItem) if (!opened) { opened = clickedItem } else if (opened == clickedItem) { opened = null } else { toggleVisibility(opened) opened = clickedItem } } const handleClick = e => { if (e.target.className.includes('dropDown')) { handleDropdown(e.target) } else if (opened) { toggleVisibility(opened) opened = null } } document.addEventListener('click', handleClick)ul { list-style: none; margin: 0; padding: 0; } ul li { width: 100px; float: left; background: #dbdbdb; line-height: 2em; text-align: center; margin: 0 5px; cursor: pointer; } ul li span { display: block; } ul li ul { display: none; } .show { display: block; }<ul> <li> <span class="dropDown">Item 1</span> <ul> <li>Sub Item 1</li> <li>Sub Item 2</li> </ul> </li> <li> <span class="dropDown">Item 2</span> <ul> <li>Sub Item 1</li> <li>Sub Item 2</li> </ul> </li> <li> <span class="dropDown">Item 3</span> <ul> <li>Sub Item 1</li> <li>Sub Item 2</li> </ul> </li> <li> <span class="dropDown">Item 4</span> <ul> <li>Sub Item 1</li> <li>Sub Item 2</li> </ul> </li> </ul>
Comments