单击菜单容器外部时如何防止页面滚动和关闭菜单

How to prevent page scroll and closing menu when click outside menu container

用解决方案编辑


我有一个边栏菜单,当我单击按钮时它会出现和消失。菜单中出现了两个问题,如下所列:

  1. 通过在 #mobile_menu div 外部单击关闭菜单,这就是我想要的。但是,菜单也会通过在 div #mobile_menu 内单击而关闭,我不希望发生这种情况,在 div 内单击菜单不应关闭。

  2. 第二个方面,打开菜单后,后页可以自由上下滚动,请问有什么办法可以避免吗?

感谢@moronator

的介入,我解决了这些问题

var mobileMenu = document.querySelector("#toggle_menu");
    function mobile_menu(e) {
        e.stopPropagation();
        var x = document.getElementById("mobile_menu");
        var y = document.getElementById("container_overlay");
        var z = document.getElementsByTagName("body")[0];
        
        // For var x - Show & Hide Menu
        if (!x.classList.contains("show")) {
          x.classList.toggle("show");
          mobileMenu.innerHTML = '<i class="icn_toggle fa-solid fa-xmark">Close Menu</i>';
        } else {
          x.classList.remove("show");
          mobileMenu.innerHTML = '<i class="icn_toggle fa-solid fa-bars">Open Menu</i>';
        }
        // For var y Show & Hide Overlay
        if (!y.classList.contains("on")) {
          y.classList.toggle("on");
        } else {
          y.classList.remove("on");
        }
        
        // For var z Prevent Page scroll with overflow
         if (!z.classList.contains("ppscroll")) {
          z.classList.toggle("ppscroll");
        } else {
          z.classList.remove("ppscroll"); 
        }
        
    }
     
        // Close Menu clicking on container_overlay
        document.getElementById("container_overlay").addEventListener("click", function (e) {
        var x = document.getElementById("mobile_menu");
        var y = document.getElementById("container_overlay");
        var z = document.getElementsByTagName("body")[0];
        
        // For var x
        if (e.target.id !== "mobile_menu" && x.classList.contains("show")) {
          x.classList.toggle("show");
          mobileMenu.innerHTML = '<i class="icn_toggle fa-solid fa-bars">Open Menu</i>';
        }
        // For var y
        if (e.target.id !== "mobile_menu" && y.classList.contains("on")) {
          y.classList.toggle("on");
        }
        // For var z
        if (e.target.id !== "mobile_menu" && z.classList.contains("ppscroll")) {
          z.classList.toggle("ppscroll");
        }
      });
/*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;
}

/*Logout Header*/
.logout_header {    
    display: flex;
    justify-content: space-between;
}

.mob {
    display: flex;
    width: 49.5%;
    justify-content: center;
    background: #fbfbfb;
    border: 1px solid #eee;
    border-radius: 4px;
    padding: 4px;
}

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

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

/*Icon Button Toggle Menu*/
#toggle_menu {
    width: 20%;
    color: #000;
    position: absolute;
    right: 20px;
    top: 20px;
}

.icn_toggle, .icn_toggle::before, .icn_toggle::after {
    margin: 0;
    z-index: 1000;
    font-size: 24px;
}

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

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

/* User Menu For header website */
#container_overlay {
    visibility: hidden;
    position: fixed;
    z-index: 998;
    top: 0;
    left: 0;
    width: 100%;
    background: #000000d6;
    opacity: 0;
    transition: 0.3s;
    height: 100vh;
}
      
#container_overlay.on {
    visibility: visible;
    opacity: 1;

}
      
.content_menu {
    display: block;
    width: 100%;
}

#mobile_menu {
    top: 0;
    left: -100%;
    padding: 20px;
    background-color: #fff;
    min-width: 160px;
    overflow-x: hidden;
    overflow-y: auto;
    z-index: 999;
    position: fixed;
    width: 75%;
    height: 100vh;
    transition: .3s;
}

#mobile_menu.show {
    left: 0;
}

.ppscroll {
    overflow: hidden;
}

/* Dropdown Button */
.dropbtn {
  background-color: #04AA6D;
  color: white;
  padding: 16px;
  font-size: 16px;
  border: none;
}

/* The container <div> - needed to position the dropdown content */
.dropdown {
  position: relative;
  display: inline-block;
}

/* Dropdown Content (Hidden by Default) */
.dropdown-content {
  display: none;
  position: absolute;
  background-color: #f1f1f1;
  min-width: 160px;
  box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
  z-index: 1;
}

/* Links inside the dropdown */
.dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}

/* Change color of dropdown links on hover */
.dropdown-content a:hover {background-color: #ddd;}

/* Show the dropdown menu on hover */
.dropdown:hover .dropdown-content {display: block;}

/* Change the background color of the dropdown button when the dropdown content is shown */
.dropdown:hover .dropbtn {background-color: #3e8e41;}
<div onclick="mobile_menu(event)" id="toggle_menu"><i class="icn_toggle fa-solid fa-bars">Open Menu</i></div>

    <div id="mobile_menu"> 
        <div class="content_menu">
            <div class="user_menu header">
              <span class="display name">Ciao [display_name]</span>
              <span class="display mail">[display_email]</span>
            </div>

            <div class="logout_header">
              <a class="mob btn-login" href="#"><span>Login</span></a>
                
              <a class="mob btn-singup" href="#"> <span>Singup</span></a>
            </div>

            <hr class="solid" />
            
            <div class="mob_menu item">
              <a href="#">
                <i class="icn_items fa-regular fa-user"></i>
                <span class="link_text">Dashboard</span>
              </a>
            </div>

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

            <div class="mob_menu item">
              <a href="#">
                <i class="icn_items fa-regular fa-cloud-arrow-down"></i>
                <span class="link_text">Downloads</span>
              </a>
            </div>

            <div class="mob_menu item">
              <a href="#">
                <i class="icn_items fa-regular fa-gear"></i>
                <span class="link_text">Impostazioni</span>
              </a>
            </div>

            <div class="mob_menu item">
              <a href="#">
                <i class="icn_items fa-regular fa-arrow-right-from-bracket"></i>
                <span class="link_text">Logout</span>
              </a>
            </div>
        </div>  
    </div>

<div id="container_overlay"></div>


包含错误的原始代码

var mobileMenu = document.querySelector("#toggle_menu");
    function mobile_menu(e) {
        e.stopPropagation();
        var x = document.getElementById("mobile_menu");
        var y = document.getElementById("container_overlay");
        
        // For var x
        if (!x.classList.contains("show")) {
          x.classList.toggle("show");
          mobileMenu.innerHTML = '<i class="icn_toggle fa-solid fa-xmark">Close Menu</i>';
        } else {
          x.classList.remove("show");
          mobileMenu.innerHTML = '<i class="icn_toggle fa-solid fa-bars">Open Menu</i>';
        }
        // For var y
        if (!y.classList.contains("on")) {
          y.classList.toggle("on");
        } else {
          y.classList.remove("on");
        }
    }
     
        // Close Menu clicking on container_overlay
        document.addEventListener("click", function (e) {
        var x = document.getElementById("mobile_menu");
        var y = document.getElementById("container_overlay");
        
        // For var x
        if (e.target.id !== "mobile_menu" && x.classList.contains("show")) {
          x.classList.toggle("show");
          mobileMenu.innerHTML = '<i class="icn_toggle fa-solid fa-bars">Open Menu</i>';
        }
        // For var y
        if (e.target.id !== "mobile_menu" && y.classList.contains("on")) {
          y.classList.toggle("on");
        }
        
      }); 
/*Items menu*/
.user_menu {
    display: flex;
    flex-direction: column;
    cursor: not-allowed;
    pointer-events: none !important;
    border: 1px solid red;
}

.error {
color: red;
}

/*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;
}

/*Logout Header*/
.logout_header {    
    display: flex;
    justify-content: space-between;
}

.mob {
    display: flex;
    width: 49.5%;
    justify-content: center;
    background: #fbfbfb;
    border: 1px solid #eee;
    border-radius: 4px;
    padding: 4px;
}

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

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

/*Icon Button Toggle Menu*/
#toggle_menu {
    display: flex;
    align-content: flex-end;
    justify-content: center;
    align-items: flex-end;
    width: 20%;
    color: #000;
    position: absolute;
    top 20px;
    right: 20px;
}

.icn_toggle, .icn_toggle::before, .icn_toggle::after {
    margin: 0;
    z-index: 1000;
    font-size: 24px;
}

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

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

/* User Menu For header website */
#container_overlay {
    visibility: hidden;
    position: fixed;
    z-index: 998;
    top: 0;
    left: 0;
    width: 100%;
    background: #000000b8;
    opacity: 0;
    transition: 0.3s;
    height: 100vh;
}
      
#container_overlay.on {
    visibility: visible;
    opacity: 1;

}
      
.content_menu {
    display: block;
    width: 100%;
}

#mobile_menu {
    top: 0;
    left: -100%;
    padding: 20px;
    background-color: #fff;
    min-width: 160px;
    overflow-x: hidden;
    overflow-y: auto;
    z-index: 999;
    position: fixed;
    width: 75%;
    height: 100vh;
    transition: .3s;
}

#mobile_menu.show {
    left: 0;
}
<div onclick="mobile_menu(event)" id="toggle_menu"><i class="icn_toggle fa-solid fa-bars"></i>Menu</div>

    <div id="mobile_menu"> 
        <div class="content_menu">

            <div class="user_menu header">
              <span class="display name">Hello [display_name]</span>
              <span class="display mail">[display_email]</span>
              <span class="error">clicking here closes the menu, it shouldn't happen.
            </div>
   
            <div class="logout_header">
              <a class="mob btn-login" href="#"><span>Login</span></a>
                
              <a class="mob btn-singup" href="#"> <span>Singup</span></a>
            </div>
            
            <hr class="solid" />
            
            <div class="mob_menu item">
              <a href="#">
                <i class="icn_items fa-regular fa-user"></i>
                <span class="link_text">Dashboard</span>
              </a>
            </div>

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

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

            <div class="mob_menu item">
              <a href="#">
                <i class="icn_items fa-regular fa-gear"></i>
                <span class="link_text">Impostazioni</span>
              </a>
            </div>

            <div class="mob_menu item">
              <a href="#">
                <i class="icn_items fa-regular fa-arrow-right-from-bracket"></i>
                <span class="link_text">Logout</span>
              </a>
            </div>
 
        </div>
    </div>

<div id="container_overlay"></div>

只需将事件侦听器添加到覆盖容器而不是整个文档:

var mobileMenu = document.querySelector("#toggle_menu");
    function mobile_menu(e) {
        e.stopPropagation();
        var x = document.getElementById("mobile_menu");
        var y = document.getElementById("container_overlay");
        
        // For var x
        if (!x.classList.contains("show")) {
          x.classList.toggle("show");
          mobileMenu.innerHTML = '<i class="icn_toggle fa-solid fa-xmark">Close Menu</i>';
        } else {
          x.classList.remove("show");
          mobileMenu.innerHTML = '<i class="icn_toggle fa-solid fa-bars">Open Menu</i>';
        }
        // For var y
        if (!y.classList.contains("on")) {
          y.classList.toggle("on");
        } else {
          y.classList.remove("on");
        }
    }
     
        // Close Menu clicking on container_overlay
        // ------- I JUST CHANGED THE FOLLOWING LINE -------
        document.getElementById("container_overlay").addEventListener("click", function (e) {
        var x = document.getElementById("mobile_menu");
        var y = document.getElementById("container_overlay");
        
        // For var x
        if (e.target.id !== "mobile_menu" && x.classList.contains("show")) {
          x.classList.toggle("show");
          mobileMenu.innerHTML = '<i class="icn_toggle fa-solid fa-bars">Open Menu</i>';
        }
        // For var y
        if (e.target.id !== "mobile_menu" && y.classList.contains("on")) {
          y.classList.toggle("on");
        }
        
      }); 
/*Items menu*/
.user_menu {
    display: flex;
    flex-direction: column;
    cursor: not-allowed;
    pointer-events: none !important;
    border: 1px solid red;
}

.error {
color: red;
}

/*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;
}

/*Logout Header*/
.logout_header {    
    display: flex;
    justify-content: space-between;
}

.mob {
    display: flex;
    width: 49.5%;
    justify-content: center;
    background: #fbfbfb;
    border: 1px solid #eee;
    border-radius: 4px;
    padding: 4px;
}

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

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

/*Icon Button Toggle Menu*/
#toggle_menu {
    display: flex;
    align-content: flex-end;
    justify-content: center;
    align-items: flex-end;
    width: 20%;
    color: #000;
    position: absolute;
    top 20px;
    right: 20px;
}

.icn_toggle, .icn_toggle::before, .icn_toggle::after {
    margin: 0;
    z-index: 1000;
    font-size: 24px;
}

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

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

/* User Menu For header website */
#container_overlay {
    visibility: hidden;
    position: fixed;
    z-index: 998;
    top: 0;
    left: 0;
    width: 100%;
    background: #000000b8;
    opacity: 0;
    transition: 0.3s;
    height: 100vh;
}
      
#container_overlay.on {
    visibility: visible;
    opacity: 1;

}
      
.content_menu {
    display: block;
    width: 100%;
}

#mobile_menu {
    top: 0;
    left: -100%;
    padding: 20px;
    background-color: #fff;
    min-width: 160px;
    overflow-x: hidden;
    overflow-y: auto;
    z-index: 999;
    position: fixed;
    width: 75%;
    height: 100vh;
    transition: .3s;
}

#mobile_menu.show {
    left: 0;
}
<div onclick="mobile_menu(event)" id="toggle_menu"><i class="icn_toggle fa-solid fa-bars"></i>Menu</div>

    <div id="mobile_menu"> 
        <div class="content_menu">

            <div class="user_menu header">
              <span class="display name">Hello [display_name]</span>
              <span class="display mail">[display_email]</span>
              <span class="error">clicking here closes the menu, it shouldn't happen.
            </div>
   
            <div class="logout_header">
              <a class="mob btn-login" href="#"><span>Login</span></a>
                
              <a class="mob btn-singup" href="#"> <span>Singup</span></a>
            </div>
            
            <hr class="solid" />
            
            <div class="mob_menu item">
              <a href="#">
                <i class="icn_items fa-regular fa-user"></i>
                <span class="link_text">Dashboard</span>
              </a>
            </div>

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

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

            <div class="mob_menu item">
              <a href="#">
                <i class="icn_items fa-regular fa-gear"></i>
                <span class="link_text">Impostazioni</span>
              </a>
            </div>

            <div class="mob_menu item">
              <a href="#">
                <i class="icn_items fa-regular fa-arrow-right-from-bracket"></i>
                <span class="link_text">Logout</span>
              </a>
            </div>
 
        </div>
    </div>

<div id="container_overlay"></div>