【问题标题】:how to close expandable menu with click outside div and js如何通过在 div 和 js 外部单击来关闭可扩展菜单
【发布时间】:2015-03-31 17:30:47
【问题描述】:

我在 js 中创建了一个可扩展的菜单。我添加了带有 click 事件的 open 类,然后再次单击以删除该类。

当我单击菜单外时,我想关闭菜单。我尝试使用 document.addEventListener 但似乎不起作用。

function collapse() {
    if (this.classList.contains('open')) {
        this.classList.remove('open');
        document.removeEventListener('click', collapse, false);
    } else {
        this.classList.add('open');
        document.addEventListener('click', collapse, false);
    }
}


var x = document.getElementsByClassName("toggle-menu");
for (var i = 0; i < x.length; i++) {
    x[i].addEventListener('click', collapse, false);
}

这里是小提琴http://jsfiddle.net/4cv220mc/

谢谢

【问题讨论】:

    标签: javascript menu


    【解决方案1】:

    我注意到,即使您单击菜单中的 li 元素之一,您发布的代码也会关闭菜单 - 这肯定是不可取的,因此最好检查仅当单击菜单的h3 元素时单击折叠事件并关闭/打开。

    其次,您在这里寻找的是event.stopPropagation 函数。这样,您可以将事件侦听器放在 toggle-menu 类和 document.documentElement 上 - 这将是 html 元素(您可以将它放在 document.body 但有时不会填满屏幕)。

    因此菜单事件侦听器将切换open 类并停止进一步传播。 html 事件监听器——现在只有在菜单事件监听器被第一次调用时才会被调用——它会检查是否有任何打开的菜单,如果有,将从所有菜单中删除open他们。

    这样您就可以拥有尽可能多的菜单,并且单击任何打开的菜单(包括另一个菜单)之外的任何位置都会将其关闭。

    这是您的 jsFiddle 的 JS 代码(我使用 [].slice.call 将所有菜单元素转换为数组,以便我可以在它们上调用 forEach 函数,我发现这更容易读/写,但是您的计数器方法当然也可以):

    var html = document.documentElement,
        menus = [].slice.call(document.getElementsByClassName('toggle-menu'));
    
    function menuClick(e){
        e.stopPropagation();
        if(e.target.tagName.toLowerCase()=='h3'){
            this.classList.toggle('open');
        }
        var openMenus = document.querySelectorAll('.open.toggle-menu');
        for(var i=0;i<openMenus.length;i++){
            if(openMenus[i]==this)
                continue;
            openMenus[i].classList.remove('open');
        }
    }
    function bodyClick(e){
        if(document.querySelector('.toggle-menu.open')){
            menus.forEach(function(menu){
                if(menu.classList.contains('open'))
                    menu.classList.remove('open');
            });
        }
    }
    menus.forEach(function(menu){
        menu.addEventListener('click',menuClick,false);
    });
    html.addEventListener('click',bodyClick,false);
    

    如果您想同时打开菜单(单击一个不应关闭其他菜单),您可以在menuClick 函数中删除从var openMenus 开始的部分。

    这是一个小提琴:http://jsfiddle.net/811r0nzw/

    【讨论】:

      【解决方案2】:

      HTML

      <div class="wrapper">
      <div class="toggle-menu">
      
      <h3 class="toggle-label">Menu</h3>
      
      <ul class="toggle-body">
          <li>1</li>
          <li>2</li>
          <li>3</li>
          <li>4</li>
          <li>5</li>
      </ul>
      </div>
      </div>
      

      CSS -

      .toggle-menu {
      background-color:#ccc;
      }
      .toggle-body {
          display:none;
      }
      .open .toggle-body {
          display:block;
      }
      .wrapper {
          width:100%;
          height:500px;
      }
      

      JS -

          function collapse() {
          if (this.classList.contains('open')) {
              this.classList.remove('open');
              document.removeEventListener('click', collapse, false);
          } else {
              this.classList.add('open');
              document.addEventListener('click', collapse, false);
          }
      }
      
      
      var x = document.getElementsByClassName("toggle-menu");
      for (var i = 0; i < x.length; i++) {
          x[i].addEventListener('click', collapse, false);
      }
      
      var y = document.getElementsByClassName("wrapper");
      for (var i = 0; i < y.length; i++) {
          y[i].addEventListener('click', collapse, false);
      }
      

      我在这里编辑了你的 jsfiddle - http://jsfiddle.net/4cv220mc/5/

      【讨论】:

        猜你喜欢
        • 2020-12-03
        • 1970-01-01
        • 2021-02-02
        • 1970-01-01
        • 2016-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多