我一直在尝试制作一个下拉按钮,当单击它外部时它会停用,但我还没有找到具有良好性能的良好解决方案,我正在使用 Astro 框架制作网站
这是我的代码:
<nav
class="hidden items-center lg:relative lg:mt-0 lg:!flex lg:basis-auto"
>
<!-- Desktop Navigation -->
<ul
class="list-style-none mr-auto flex flex-col pl-0 lg:flex-row"
>
{navData.map(data => {
if(data.dropdown === true) {
return (
<li data-title={data.title} class="sm:block relative dropdowns mx-2 lg:flex ">
<button data-title={data.title} class="dropdown text-sm rounded flex gap-1 items-center">
{data.title}
<svg viewBox="0 0 1024 1024" class="icon w-3" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><path d="M903.232 256l56.768 50.432L512 768 64 306.432 120.768 256 512 659.072z" ></path></g></svg>
</button>
<div data-title={data.title} class="absolute right-0 top-7 mt-2 w-48 bg-gray-800 rounded-md overflow-hidden z-10 hidden">
{data.subcat.map(el => (
<a href={el.slug} class="block px-4 py-2 text-sm text-gray-200 hover:bg-gray-700">
{el.title}
</a>
))}
</div>
</li>
)}
else {
return (
<li class="mb-4 pl-2 lg:mb-0 lg:pl-0 lg:pr-1" data-te-nav-item-ref>
<a
class="p-0 text-sm transition duration-200 hover:ease-in-out motion-reduce:transition-none lg:px-2"
href={`${data.slug}`}
data-te-nav-link-ref
>
{data.title}
</a>
</li>
)
}
})}
</ul>
</nav>
const dropdownToggle = document.querySelectorAll('.dropdown');
const dropdownMenu = document.querySelectorAll('.dropdowns > div');
dropdownToggle.forEach(button => button.addEventListener('click', () => {
dropdownMenu.forEach((el) => {
if(button.getAttribute('data-title') === el.getAttribute('data-title')){
el.classList.toggle('hidden')
}
});
}))
我尝试过使用 focus-within 但没有达到预期效果
.dropdowns:focus-within > div {
display: block;
}
我认为这个解决方案:
window.onclick = function(event) {
if (!event.target.matches('.dropbtn')) {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
对性能不利
这对性能来说并不坏,因为您需要一个点击处理程序,它会在下拉菜单关闭时发出通知。你不应该优化那些不慢的东西,因为你有可能会使你的代码变得过于复杂,而这些东西将难以维护并且可能也更慢。
但是,如果您确实注意到一些性能问题(例如当您有数千个下拉菜单的情况下),那么您可以简单地创建一些资源,为了简单起见,让我们调用
currentDropdown
和:
currentDropdown
并且与您刚刚打开的下拉列表不匹配(如果您打开了下拉列表),则将其折叠currentDropdown
设置为它currentDropdown
设置为 undefined
currentDropdown
设置为 undefined
因此,您最多只能处理一个下拉列表,而不是循环所有下拉列表。
如果您真的想避免在没有打开下拉菜单时在下拉菜单之外发生点击事件(但我不推荐这样做),那么每当您在任何下拉菜单之外单击时都可以
removeEventListener
,以便在外部单击当您不需要时,下拉列表不会触发事件侦听器。但是,我再次不推荐这样做,因为它会使代码变得复杂,而且几乎没有任何好处。如上所述避免循环应该足够了。