开发者问题收集

点击锚标签时隐藏导航(Vanilla JavaScript)

2018-01-11
525

我有一个在小屏幕上显示的导航。我的目标是每次单击导航中的锚点标签时隐藏该导航。 到目前为止,我尝试了多种选择,但似乎都没有用。我认为真正的问题是我不知道如何选择菜单中的所有锚点标签。我正在寻找的解决方案必须是纯 JS。提前谢谢您。

<nav id="mySidenav" class="sidenav">
               <a href="#about">About</a>
               <a href="#services" onclick="closeNav();">Services</a>
               <a href="#contact">Contact</a>
</nav>



.sidenav {
          width: 0;
         }
.sidenav.mobile-only {
         width:250px;
                     }

function closeNav() {
   myNav.classList.remove("mobile-only");
 }

选项 1

 var anchorTags = document.querySelectorAll('a')
 anchorTags.addEventListener('click', closeNav(), false);
 ** Uncaught TypeError: anchorTags.addEventListener is not a function

选项 2

 var anchorTags = document.getElementsByTagName("a")
 anchorTags.addEventListener('click', closeNav());
 **Uncaught TypeError: anchorTags.addEventListener is not a function

选项 3

 var anchorTags = document.querySelector("mobile-only a");
    for (var x = 0; x < anchorTags.length; x++) {
        anchorTags[x].addEventListener("click", function() {
            closeNav();
    });
    };

    **Uncaught TypeError: Cannot read property 'length' of null

我发现的唯一解决方案是内联添加函数,但我确信一定有更好的解决方案。

<a href="#about" onclick="closeNav();">About</a>
<a href="#services" onclick="closeNav();">Services</a>
<a href="#contact" onclick="closeNav();">Portofolio</a>

后期编辑: 选项 4:获胜者(有比这更好的解决方案,如下所示。谢谢大家)

var anchorTags = document.getElementById("mySidenav").childNodes;
for (var x = 0; x < anchorTags.length; x++) {
    anchorTags[x].addEventListener("click", function() {
        closeNav();
});
};

感谢大家的回复,我终于明白问题出在哪里了。我尝试了你们所有的解决方案,它们都运行良好。

3个回答

我们将采用选项 3,因为它最接近解决方案。

您应该使用 document.querySelectorAll('nav a') 或更好的 document.querySelectorAll('.sidenav a') 。这将为您提供与我们的选择器匹配的所有元素的节点列表。之后,我们可以使用 forEach 循环遍历每个节点并绑定我们的点击事件。

document.querySelectorAll('.sidenav a').forEach(function(a) {
    a.addEventListener('click', closeNav);
});

请注意,我使用了 closeNav 而不是 closeNav() - () 很重要!使用 () 将尝试立即调用该函数,而不是将该函数分配为事件的处理程序。

Wild Beard
2018-01-11

在选项 1 中,运行 querySelectorAll 后返回的是 nodeList ,类似于数组。您无法将事件侦听器添加到列表本身,您需要将侦听器添加到列表中的每个项目,类似于您在选项 3 中尝试执行的操作。在选项 2 中,这是同样的问题,但这次使用的是 HTMLCollection 。在选项 3 中,您执行的是 querySelector ,而不是 querySelectorAll ,后者仅返回与选择器匹配的第一个元素。因此如果您尝试使用 querySelectorAll 的选项 3,它应该可以工作。

RyanDay
2018-01-11

当您使用 getElementsByTagName 时,它返回的是一个 Node 集合,而不是 HTMLElement,因此您需要循环它以向每个元素添加事件侦听器

var anchorTags = document.getElementsByTagName("a");
[...anchorTags].map(elem => elem.addEventListener('click', closeNav));

querySelector 相同,它返回一个 HTMLElement(只有一个),如果您希望它们全部使用 querySelectorAll ,您需要向它传递一个 CSS 选择器

var anchorTags = document.querySelector("a.mobile-only");
[...anchorTags].map(elem => elem.addEventListener('click', closeNav));

我使用数组展开 [...arraish_element] 为 Node Collection 提供真实数组的所有方法,并能够在那里使用 map,或者您只需使用 for 和 nodecollection 的长度即可

Nicolas M. Pardo
2018-01-11