【问题标题】:Can someone tell me what's wrong with my dropdown menu javascript code有人可以告诉我我的下拉菜单 javascript 代码有什么问题吗
【发布时间】:2019-09-10 19:09:56
【问题描述】:

我一直在学习 Javascript,并且作为一些练习,我想我会为自己创建一个下拉导航菜单,它可以通过“点击”而不是悬停来工作。我已经创建了下面的代码(不起作用),我想知道是否有人可以解释原因,以便我可以看到我哪里出错了。

我可以打开下拉菜单,但是当我添加关闭下拉菜单的代码时,下拉菜单甚至没有打开。

我希望有人能指出我正确的方向,这样我就可以知道我哪里出了问题,并且我可以在以后避免此类问题

(function() {
  let menuHeader = document.querySelectorAll('.menu-item-has-children');
  let subMenu = document.querySelector('.sub-menu');
  menuHeader.forEach(function(btn) {
    btn.addEventListener('click', function(event) {
      event.preventDefault();
      subMenu.classList.add('nav-open');
      // Close if anywhere on screen aprt form menu is clicked
      if (subMenu.classList.contains('nav-open')) {
        window.onclick = function(event) {
          if (!event.target.classList.contains('sub-menu')) {
            subMenu.classList.remove('nav-open');
          }
        };
      };
    });
  });


})();
<nav class="main-nav">
  <ul>
    <li><a href="" title="Home">Home</a></li>
    <li class="menu-item-has-children"><a href="#" title="What We Do">What We Do</a>
      <ul class="sub-menu">
        <li><a href="" title="">Page 1</a></li>
        <li><a href="" title="">Page 2</a></li>
        <li><a href="" title="">Page 3</a></li>
        <li><a href="" title="">Page 4</a></li>
        <li><a href="" title=" ">Page 5</a></li>
        <li><a href="" title="">Page 6</a></li>
      </ul>
    </li>
    <li class="menu-item-has-children"><a href="#" title="Our Work">Our Work</a>
      <ul class="sub-menu">
        <li><a href="" title="">Portfolio 1</a></li>
        <li><a href="" title="">Portfolio 2</a></li>
        <li><a href="" title="">Portfolio 3</a></li>
        <li><a href="" title="">Portfolio 4</a></li>
        <li><a href="" title="">Portfolio 5</a></li>
      </ul>
    </li>
    <li><a href="" title="">Contact</a></li>
  </ul>
</nav>

按照要求,CSS如下

.main-nav ul > li   {
    display: inline;
    position: relative;
}


.main-nav ul li  a  {
    display: inline-block;
    font-family: bebas-neue, sans-serif;
    font-style: normal;
    font-weight: 400;
    text-decoration: none;
    color: #333;
    font-size: 1.3em;
    padding: 0.5em 0.8em 0.8em 0.8em;
    transition: background 0.2s linear;
}

.main-nav ul li  a:hover    {
    background: #00a492;
    color: #fff;
}

.main-nav ul li a:not(:only-child):after {
    content: '\25bc';
    font-size: 0.6em;
    position: relative;
    top: -4px;
    left: 2px;
}



/* Second Level of Navigation */

.main-nav ul li  ul {
    width: 250px;
    position: absolute;
    top: 160%;
    left: 0;
    background: #00a492;
}

.main-nav ul li  ul li a    {
    display: block;
}

.sub-menu   {
    display: none;
}

.nav-open   {
    display: block;
}

.slicknav_menu {
    display:none;
}

.highlight-btn  {
    background: #00a492 !important;
    color: #fff !important;
}

``

【问题讨论】:

  • 你也可以显示 CSS 吗?那里也可能是个问题

标签: javascript html css


【解决方案1】:

考虑改用事件委托。单击页面上的任何位置时,运行事件侦听器。如果单击的目标不在 LI 内,则从具有 .nav-open 的现有元素中删除 .nav-open(如果有的话)。否则,如果单击的目标是 &lt;a&gt;(外部 .menu-item-has-children 的后代),则导航到它的第二个孩子 (.children[1]) 并向其添加类:

function closeOpenNav() {
  const currentOpen = document.querySelector('.nav-open');
  if (currentOpen) {
    currentOpen.classList.remove('nav-open');
  }
}

window.addEventListener('click', (event) => {
  const li = event.target.closest('.menu-item-has-children');
  if (!li) {
    // Close if anywhere on screen aprt form menu is clicked
    console.log('closing');
    closeOpenNav();
    return;
  }
  if (event.target.parentElement !== li) {
    // The clicked element is a descendant of a `.nav-open`
    // so, don't do anything
    return;
  }
  event.preventDefault();
  closeOpenNav();
  const thisSubMenu = li.children[1];
  thisSubMenu.classList.add('nav-open');
});
.sub-menu {
  display: none;
}
.nav-open {
  display: block;
}
<nav class="main-nav">
  <ul>
    <li><a href="" title="Home">Home</a></li>
    <li class="menu-item-has-children"><a href="#" title="What We Do">What We Do</a>
      <ul class="sub-menu">
        <li><a href="" title="">Page 1</a></li>
        <li><a href="" title="">Page 2</a></li>
        <li><a href="" title="">Page 3</a></li>
        <li><a href="" title="">Page 4</a></li>
        <li><a href="" title=" ">Page 5</a></li>
        <li><a href="" title="">Page 6</a></li>
      </ul>
    </li>
    <li class="menu-item-has-children"><a href="#" title="Our Work">Our Work</a>
      <ul class="sub-menu">
        <li><a href="" title="">Portfolio 1</a></li>
        <li><a href="" title="">Portfolio 2</a></li>
        <li><a href="" title="">Portfolio 3</a></li>
        <li><a href="" title="">Portfolio 4</a></li>
        <li><a href="" title="">Portfolio 5</a></li>
      </ul>
    </li>
    <li><a href="" title="">Contact</a></li>
  </ul>
</nav>

【讨论】:

    【解决方案2】:

    我认为这可能会发生,因为首先您添加nav-open 类而不是检查它是否存在,如果是,您正在向窗口添加事件(窗口仍然可以捕获此事件)并删除该类,所以什么都不应该发生。尝试在event.preventDefault()下添加event.stopPropagation()

    (function() {
      let menuHeader = document.querySelectorAll('.menu-item-has-children');
      let subMenu = document.querySelector('.sub-menu');
      menuHeader.forEach(function(btn) {
        btn.addEventListener('click', function(event) {
          event.preventDefault();
          event.stopPropagation()
          subMenu.classList.add('nav-open');
          // Close if anywhere on screen aprt form menu is clicked
          if (subMenu.classList.contains('nav-open')) {
            window.onclick = function(event) {
              if (!event.target.classList.contains('sub-menu')) {
                subMenu.classList.remove('nav-open');
              }
            };
          };
        });
      });
    
    
    })();```
    

    【讨论】:

    • 您好,感谢您抽出宝贵时间发表评论。我试过了,看起来效果不错,但是,它只打开第一个子菜单,所以不起作用。
    • 可能是因为subMenu 是数组,所以您只将它应用于subMenu 数组的第一个元素;)
    • 如果你想在你的所有 subMenu 元素上都有这种行为,你必须遍历 subMenu 数组;)
    • 谢谢。正如您可能会说的那样,我非常喜欢这个。 :-)
    【解决方案3】:

    这是一个工作演示

    (function() {
      let menuHeader = document.querySelectorAll('.menu-item-has-children');
      let subMenus = document.querySelectorAll('.sub-menu');
      menuHeader.forEach(function(btn) {
        btn.querySelector('a').addEventListener('click', function(event) {
          event.preventDefault();
    			event.stopImmediatePropagation();
          closeAllMenus();
          btn.querySelector('.sub-menu').classList.add('nav-open');
        });
      });
    
      document.addEventListener("click", function(){
      	closeAllMenus();
      });
      
      function closeAllMenus(){
      	subMenus.forEach(function(ele) {
        	ele.classList.remove('nav-open');
        });
      }
    
    
    })();
    .sub-menu{
      display: none;
    }
    .sub-menu.nav-open{
      display: block;
    }
    <nav class="main-nav">
      <ul>
        <li><a href="" title="Home">Home</a></li>
        <li class="menu-item-has-children">
          <a href="#" title="What We Do">What We Do</a>
          <ul class="sub-menu">
            <li><a href="" title="">Page 1</a></li>
            <li><a href="" title="">Page 2</a></li>
            <li><a href="" title="">Page 3</a></li>
            <li><a href="" title="">Page 4</a></li>
            <li><a href="" title=" ">Page 5</a></li>
            <li><a href="" title="">Page 6</a></li>
          </ul>
        </li>
        <li class="menu-item-has-children"><a href="#" title="Our Work">Our Work</a>
          <ul class="sub-menu">
            <li><a href="" title="">Portfolio 1</a></li>
            <li><a href="" title="">Portfolio 2</a></li>
            <li><a href="" title="">Portfolio 3</a></li>
            <li><a href="" title="">Portfolio 4</a></li>
            <li><a href="" title="">Portfolio 5</a></li>
          </ul>
        </li>
        <li><a href="" title="">Contact</a></li>
      </ul>
    </nav>

    你的代码中的第一个错误是声明了这个

    let subMenu = document.querySelector('.sub-menu');
    

    这总是第一个子菜单,所以我把它删除了。 如果你想获得每个元素的子菜单,你应该这样做:

    btn.querySelector('.sub-menu')
    

    所以现在它将为你已经完成的 forEach 中的每个元素获取子菜单。


    要在单击文档时关闭菜单,我只是在单击文档时创建了一个事件侦听器,它将从任何子菜单中删除 nav-open 类。

    document.addEventListener("click", function(){
        subMenus.forEach(function(ele) {
            ele.classList.remove('nav-open');
        });
      });
    

    【讨论】:

    • 嗨,感谢您抽出时间来解释我哪里出错了。您建议的代码在打开/关闭菜单方面有效,但我不喜欢它如何同时打开多个菜单。我真的很感谢你的帮助
    • 我刚刚编辑了代码并添加了一个关闭所有打开的子菜单的功能,这样您就可以在任何需要的地方使用它。检查一下。
    【解决方案4】:

    也许是这样,代码应该是不言自明的

    // Dropdown Menu
        (function(){
          let menuHeader = document.querySelectorAll('.menu-item-has-children');
          menuHeader.forEach(function(btn){
            btn.addEventListener('click', function(event){
              event.preventDefault();
              
              if(this.classList.contains('nav-open')) {
                  return this.classList.remove('nav-open');
              }
              
              var openNavPoints = document.querySelectorAll('.menu-item-has-children.nav-open');
              if(openNavPoints.length >= 1) {
                  [...openNavPoints].forEach(function(openNavPoint) {
                      openNavPoint.classList.remove('nav-open');
                  });
              }
              this.classList.add('nav-open');
              
            });
          });
        })();
    .menu-item-has-children .sub-menu {
        display: none;
    }
    .menu-item-has-children.nav-open .sub-menu {
        display: block;
    }
    <nav class="main-nav">
    <ul>
            <li><a href="" title="Home">Home</a></li>
            <li class="menu-item-has-children"><a href="#" title="What We Do">What We Do</a>
                <ul class="sub-menu">
                    <li><a href="" title="">Page 1</a></li>
                    <li><a href="" title="">Page 2</a></li>
                    <li><a href="" title="">Page 3</a></li>
                    <li><a href="" title="">Page 4</a></li>
                    <li><a href="" title=" ">Page 5</a></li>
                    <li><a href="" title="">Page 6</a></li>
                </ul></li>
            <li class="menu-item-has-children"><a href="#" title="Our Work">Our Work</a>
                <ul  class="sub-menu">
                    <li><a href="" title="">Portfolio 1</a></li>
                    <li><a href="" title="">Portfolio 2</a></li>
                    <li><a href="" title="">Portfolio 3</a></li>
                    <li><a href="" title="">Portfolio 4</a></li>
                    <li><a href="" title="">Portfolio 5</a></li>
                </ul>
            </li>
            <li><a href="" title="">Contact</a></li>
        </ul>
    </nav>

    【讨论】:

    • 感谢您的帮助,但恐怕这不起作用
    • @Ross “它不起作用”是什么意思?如果打开,您希望它折叠吗?我已经更新了答案现在也适用于“切换”(如果打开则折叠)
    • 您好,当我点击屏幕时菜单没有关闭。没问题,因为我现在已经整理好了。感谢您的帮助
    猜你喜欢
    • 1970-01-01
    • 2019-12-02
    • 1970-01-01
    • 1970-01-01
    • 2020-02-21
    • 2020-10-30
    • 2010-11-08
    • 1970-01-01
    相关资源
    最近更新 更多