点击外部时关闭下拉按钮但性能良好

问题描述 投票:0回答:1

我一直在尝试制作一个下拉按钮,当单击它外部时它会停用,但我还没有找到具有良好性能的良好解决方案,我正在使用 Astro 框架制作网站

所以这是我想要的一个例子: example

这就是我所拥有的:my website

这是我的代码:


<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');
      }
    }
  }
}

对性能不利

javascript css drop-down-menu dropdown astro
1个回答
0
投票

这对性能来说并不坏,因为您需要一个点击处理程序,它会在下拉菜单关闭时发出通知。你不应该优化那些不慢的东西,因为你有可能会使你的代码变得过于复杂,而这些东西将难以维护并且可能也更慢。

但是,如果您确实注意到一些性能问题(例如当您有数千个下拉菜单的情况下),那么您可以简单地创建一些资源,为了简单起见,让我们调用

currentDropdown
和:

  • 每当发生点击时,如果之前设置了
    currentDropdown
    并且与您刚刚打开的下拉列表不匹配(如果您打开了下拉列表),则将其折叠
  • 每当打开下拉菜单时,只需将
    currentDropdown
    设置为它
  • 每当在任何下拉菜单之外发生点击时,请确保不要忘记将
    currentDropdown
    设置为
    undefined
  • 如果您需要在选择其中的某个项目后关闭下拉列表,请将
    currentDropdown
    设置为
    undefined

因此,您最多只能处理一个下拉列表,而不是循环所有下拉列表。

如果您真的想避免在没有打开下拉菜单时在下拉菜单之外发生点击事件(但我不推荐这样做),那么每当您在任何下拉菜单之外单击时都可以

removeEventListener
,以便在外部单击当您不需要时,下拉列表不会触发事件侦听器。但是,我再次不推荐这样做,因为它会使代码变得复杂,而且几乎没有任何好处。如上所述避免循环应该足够了。

© www.soinside.com 2019 - 2024. All rights reserved.