单击容器外时如何关闭 sidenav 菜单 div

How to close sidenav menu when click out of container div

我正在构建一个 sidenav 菜单,它会在单击按钮时出现和消失。我在这里学到了很多关于堆栈的知识,到目前为止用户帮助我,但现在我无法集成一个功能。

正如您在代码中看到的,如果您单击按钮菜单,则 sidenav 会在您再次按下时打开或关闭。除了可以正常工作的按钮外,我还希望能够在 div 容器外部单击时关闭菜单。我尝试做一些事情,结果只有一半,问题是现在即使不单击按钮也会打开菜单,页面上的所有其他元素显然都不起作用。我想这是因为 .mts_mob_container 占据了整个宽度,但如果我不这样做,我怎么能通过在 div 之外单击来关闭菜单?

我做错了一些明显的错误,但我不知道是什么。我还是一个初学者,对于很多错误感到抱歉。有人能帮我吗 ?感谢您的回复,谢谢。

编辑:代码在堆栈和 jsfiddle 上有效,但在我的网站上除外。 感谢@user2495207 的干预,菜单按我的意愿工作!我试着把所有东西都放在我的网站上(我把它放在 header 菜单中),它用按钮打开和关闭,但是当我在 div 外面单击时它不会关闭。

如您所见,它可以正常工作。我错过了什么吗?

var menu = document.querySelector(".mob_menu_button");
function mobile_menu() {
  var x = document.getElementById("mts_mobile_menu");
  if (!x.classList.contains("side_show")) {
    x.classList.add ("side_show");
    menu.innerHTML = 'Close Menu';
    
  } else { 
    x.classList.add("side_hide");
    menu.innerHTML = 'Open Menu';

    setTimeout(function(){
     x.classList.remove("side_show");
     x.classList.remove("side_hide");  
    },300)
  }
}

document.addEventListener("click", function (e) {
        var x = document.getElementById("mts_mobile_menu");
        if (e.target.localName == "html" && x.classList.contains("side_show")) {

          x.classList.add("side_hide");
          menu.innerHTML = "<span>Open menu</span>";

          setTimeout(function () {
            x.classList.remove("side_show");
            x.classList.remove("side_hide");
          }, 300);
        }
      });
/*Items menu*/
.user_menu {
  display: flex;
  flex-direction: column;
}


/*Menu header info*/
.display.name {
  font-size: 15px;
  font-weight: 500;
  color: #303238;
}

.display.mail {
  font-size: 13px;
  color: #3d5afe;
}

hr.solid {
  border-top: 1px solid #e0e0e0;
  margin: 10px 0px 10px 0px;
}


/*Text Link css*/
.user_menu.item>a {
  display: flex;
  justify-content: flex-start;
  align-items: center;
  padding: 8px 0;
  font-size: 13px;
  color: #75777D;
}

.user_menu.item:hover>a {
  color: #2E323A;
}

/*Icon Button Toggle Menu*/
.mob_menu_button {
    display: flex;
    align-items: center;
    width: 120px;
    position: absolute;
    top: 10px;
    right: 10px;
    background: #fbfbfb!important;
    font-weight: 500!important;
    justify-content: center;
}

.icn_button {
  margin: 0;
  font-size: 14px;
}

.icn_button:before {
  margin: 0;
}

.icn_button:after {
  margin: 0;
}


/*Icon Items Menu*/
.icn_menu:before,
.icon_menu:after {
  margin: 0px;
  padding: 0px;
  font-size: 16px
}

.icn_menu {
  margin-right: 10px;
  display: flex !important;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
}


/* User Menu For header website */

.mts_mob_container {
  display:flex;
  position:fixed;
  z-index: 999;
  height: 100%;
  top: 0;
  left: 0;
}

.mts_sidenav_box {
    display: block;
}

.mts_sidenav_content {
  display: none;
  padding: 20px;
  background-color: #fff;
  min-width: 160px;
  width: 280px;
  border-radius: 3px;
  overflow-x: hidden;
  overflow-y: auto;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  z-index: 999;
  position: relative;
  animation: animateFromLeft .3s;
}

@keyframes animateFromLeft {
  from {
    left: -500px;
    opacity: 0;
  }
  to {
    left: 0;
    opacity: 1;
  }
}

@keyframes animateToLeft {
  from {
    left: 0;
    opacity: 1;
  }
  to {
    left: -500px;
    opacity: 0;
  }
}

.side_show {
  display: block !important;
  height: 100vh;
  overflow: hidden;
  width: 100%;
}

.mts_sidenav_content.side_hide {
  animation: animateToLeft .4s;
}
<button onclick="mobile_menu()" class="mob_menu_button">Open Menu</button>
<div class="mts_mob_container">
  <div class="mts_sidenav_box">
      
   <div id="mts_mobile_menu" class="mts_sidenav_content">
       
    <div class="user_menu header">
        <span class="display name">Ciao [display_name]</span>
        <span class="display mail">[display_email]</span>
    </div>   
      
     <hr class="solid">  
     
    <div class="user_menu item">
        <a href="/account">
         <i class="icn_menu fa-regular fa-user"></i>
         <span class="link_text">Dashboard</span>
        </a>
    </div>
    
     <div class="user_menu item">
        <a href="ordini">
         <i class="icn_menu fa-regular fa-basket-shopping"></i>
         <span class="link_text">I miei ordini</span>
        </a>
    </div>
    
    <div class="user_menu item">
        <a href="libreria">
         <i class="icn_menu fa-regular fa-cloud-arrow-down"></i>
         <span class="link_text">Downloads</span>
        </a>
    </div>
    
    <div class="user_menu item">
        <a href="impostazioni">
         <i class="icn_menu fa-regular fa-gear"></i>
         <span class="link_text">Impostazioni</span>
        </a>
    </div>
    
    <div class="user_menu item">
        <a href="wp-login.php?action=logout">
         <i class="icn_menu fa-regular fa-arrow-right-from-bracket"></i>
         <span class="link_text">Logout</span>
        </a>
    </div>
   </div>
    
  </div>
</div>

如果您在浏览器中检查 .mts_mob_container 元素,您会发现它覆盖了按钮(该按钮未触发任何事件)所以我不得不评论它的尺寸:

.mts_mob_container {
        display: flex;
        position: fixed;
        z-index: 999;
        /* height: 100%; */
        top: 0;
        left: 0;
        /* width: 100%;*/
      }

我也加了这个block,当用户在sidenav外面点击时的一个事件,里面的代码和mobile_menu关闭sidenav的函数的else部分是一样的。

      document.addEventListener("click", function (e) {
        var x = document.getElementById("mts_mobile_menu");
        if (e.target.id !== "mts_mobile_menu" && x.classList.contains("side_show")) {
          x.classList.add("side_hide");
          menu.innerHTML = "<span>Open menu</span>";

          var y = document.getElementById("closing_div");
          if (!x.classList.contains("side_show")) {
            x.classList.add("side_hide");
          }

          setTimeout(function () {
            x.classList.remove("side_show");
            x.classList.remove("side_hide");
          }, 500);
        }
      });

更新:
按钮事件正在传播到其父级 document 所以我添加了 e.stopPropagation();.
document 的情况下; if 语句 if(e.target.id !== "mts_mobile_menu" && x.classList.contains("side_show")) 意味着如果点击的目标不是 sidenav 并且显示

var menu = document.querySelector(".mob_menu_button");
      function mobile_menu(e) {
        e.stopPropagation();
        var x = document.getElementById("mts_mobile_menu");
        if (!x.classList.contains("side_show")) {
          x.classList.add("side_show");
          menu.innerHTML = "<span>Close menu</span>";
        } else {
          x.classList.add("side_hide");
          menu.innerHTML = "<span>Open menu</span>";

          var y = document.getElementById("closing_div");
          if (!x.classList.contains("side_show")) {
            x.classList.add("side_hide");
          }

          setTimeout(function () {
            x.classList.remove("side_show");
            x.classList.remove("side_hide");
          }, 500);
        }
      }
      document.addEventListener("click", function (e) {
        var x = document.getElementById("mts_mobile_menu");
        if (e.target.id !== "mts_mobile_menu" && x.classList.contains("side_show")) {
          x.classList.add("side_hide");
          menu.innerHTML = "<span>Open menu</span>";

          var y = document.getElementById("closing_div");
          if (!x.classList.contains("side_show")) {
            x.classList.add("side_hide");
          }

          setTimeout(function () {
            x.classList.remove("side_show");
            x.classList.remove("side_hide");
          }, 500);
        }
      });
  * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      /*Items menu*/
      .user_menu {
        display: flex;
        flex-direction: column;
      }

      /*Menu header info*/
      .display.name {
        font-size: 15px;
        font-weight: 500;
        color: #303238;
      }

      .display.mail {
        font-size: 13px;
        color: #3d5afe;
      }

      hr.solid {
        border-top: 1px solid #e0e0e0;
        margin: 10px 0px 10px 0px;
      }

      /*Text Link css*/
      .user_menu.item > a {
        display: flex;
        justify-content: flex-start;
        align-items: center;
        padding: 8px 0;
        font-size: 13px;
        color: #75777d;
      }

      .user_menu.item:hover > a {
        color: #2e323a;
      }

      /*Icon Button Toggle Menu*/
      .mob_menu_button {
        display: flex;
        align-content: center;
        justify-content: center;
        align-items: center;
        width: 100px;
        position: absolute;
        top: 10px;
        right: 10px;
        background: #fbfbfb !important;
        font-weight: 500 !important;
      }

      .icn_button {
        margin: 0;
        font-size: 14px;
      }

      .icn_button:before {
        margin: 0;
      }

      .icn_button:after {
        margin: 0;
      }

      /*Icon Items Menu*/
      .icn_menu:before,
      .icon_menu:after {
        margin: 0px;
        padding: 0px;
        font-size: 16px;
      }

      .icn_menu {
        margin-right: 10px;
        display: flex !important;
        align-items: center;
        justify-content: center;
        width: 22px;
        height: 22px;
      }

      /* User Menu For header website */
      .mts_mob_container {
        display: flex;
        position: fixed;
        z-index: 999;
        /* height: 100%; */
        top: 0;
        left: 0;
        /* width: 100%;*/
      }

      .mts_sidenav_box {
        display: block;
      }

      .mts_sidenav_content {
        display: none;
        padding: 20px;
        background-color: #fff;
        min-width: 160px;
        width: 280px;
        border-radius: 3px;
        overflow-x: hidden;
        overflow-y: auto;
        box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
        z-index: 999;
        position: relative;
        animation: animateFromLeft 0.6s;
      }

      @keyframes animateFromLeft {
        from {
          left: -500px;
          opacity: 0;
        }
        to {
          left: 0;
          opacity: 1;
        }
      }

      @keyframes animateToLeft {
        from {
          left: 0;
          opacity: 1;
        }
        to {
          left: -500px;
          opacity: 0;
        }
      }

      .side_show {
        display: block !important;
        height: 100vh;
        overflow: hidden;
        width: 100%;
      }

      .mts_sidenav_content.side_hide {
        animation: animateToLeft 0.6s;
      }
    <button onclick="mobile_menu(event)" class="mob_menu_button">Open menu</button>

    <div class="closing_div">
      <div class="mts_mob_container">
        <div class="mts_sidenav_box">
          <div id="mts_mobile_menu" class="mts_sidenav_content">
            <div class="user_menu header">
              <span class="display name">Ciao [display_name]</span>
              <span class="display mail">[display_email]</span>
            </div>

            <hr class="solid" />

            <div class="user_menu item">
              <a href="/account">
                <i class="icn_menu fa-regular fa-user"></i>
                <span class="link_text">Dashboard</span>
              </a>
            </div>

            <div class="user_menu item">
              <a href="ordini">
                <i class="icn_menu fa-regular fa-basket-shopping"></i>
                <span class="link_text">I miei ordini</span>
              </a>
            </div>

            <div class="user_menu item">
              <a href="libreria">
                <i class="icn_menu fa-regular fa-cloud-arrow-down"></i>
                <span class="link_text">Downloads</span>
              </a>
            </div>

            <div class="user_menu item">
              <a href="impostazioni">
                <i class="icn_menu fa-regular fa-gear"></i>
                <span class="link_text">Impostazioni</span>
              </a>
            </div>

            <div class="user_menu item">
              <a href="wp-login.php?action=logout">
                <i class="icn_menu fa-regular fa-arrow-right-from-bracket"></i>
                <span class="link_text">Logout</span>
              </a>
            </div>
          </div>
        </div>
      </div>
    </div>