当我在侧边栏外单击时关闭侧边栏

Close a sidebar when I click outside of it

我试图在点击边栏外部时关闭它。 我添加了一个条件,仅在它打开时关闭它 (nav_active),但我遗漏了一些东西。 预期的行为是在我单击红框内部或外部时显示警报。

解后编辑 我刚刚意识到第一次点击会在外面,所以当我删除活动 class 时,滑块将永远不会显示

"use strict";

var burger = document.querySelector('.burger');
var nav = document.querySelector('.nav_links');

burger.addEventListener('click', function () {
    nav.classList.toggle('nav_active');
  });

if (nav.classList.contains("nav_active")) { 

window.addEventListener('click', function(e) {   
      
    nav.classList.remove('nav_active');
      });
    }
.nav_home, .nav_links, .nav_buttons, .nav_list {
  display: inline-block;
  vertical-align: middle;
}

.burger {
  width: 2.4rem;
  height: 2.4rem;
  margin: auto 0;
  cursor: pointer;
  background: black;
}


.nav_list a:hover {
  text-decoration: line-through !important;
}


  .nav_links {
    display: block;
    z-index: 0;
    position: absolute;
    right: 0rem;
    width: 80%;
    margin-right: 0.1rem;
    border-left: 0.1rem solid;
    background: red;
  }

  .nav_item {
    display: block;
  }

  .nav_list {
    display: block;
    a {
      display: block;
    }
    span {
      display: none;
    }
  }
  
  .nav_active {
  background: blue;
  display: inline-block;
}
<header id="header">

  <div class="header container">


    <div class="nav_links">

      <h5 class="nav_list">
        <span class="noselect">⁄</span>
      </h5>

      <div class="nav_buttons">

        <h5 class="theme-label"></h5>

      </div>

    </div>

    <div class="burger"></div>

  </div>

</header>

您只需将代码移动到您的侦听器中 - 我重新格式化了您将变量分配给函数的方式。最后,我在关闭时删除了 window 事件侦听器。

"use strict";

var burger = document.querySelector('.burger');
var nav = document.querySelector('.nav_links');

const navSlide = () => {
  burger.addEventListener('click', function(ev) {
    nav.classList.toggle('nav_active');
    if (nav.classList.contains("nav_active")) {
      window.addEventListener('click', captureClick);
      console.log("ADDED WINDOW LISTENER")
    } else {
      // remove the window event listener
      window.removeEventListener('click', captureClick);
      console.log("REMOVED WINDOW LISTENER")
    }
  });
};

const captureClick = (e) => {
  if (nav.contains(e.target)) {
    alert("Clicked in Box");
  } else {
    alert("Clicked outside Box");
  }
}
navSlide();
.nav_home,
.nav_links,
.nav_buttons,
.nav_list {
  display: inline-block;
  vertical-align: middle;
}

.burger {
  width: 2.4rem;
  height: 2.4rem;
  margin: auto 0;
  cursor: pointer;
  background: black;
}

.nav_list a:hover {
  text-decoration: line-through !important;
}

.nav_links {
  display: block;
  z-index: 0;
  position: absolute;
  right: 0rem;
  width: 80%;
  margin-right: 0.1rem;
  border-left: 0.1rem solid;
  background: red;
}

.nav_item {
  display: block;
}

.nav_list {
  display: block;
  a {
    display: block;
  }
  span {
    display: none;
  }
}

.nav_active {
  display: inline-block;
}
<header id="header">
  <div class="header container">
    <div class="nav_links">
      <h5 class="nav_list">
        <span class="noselect">⁄</span>
      </h5>
      <div class="nav_buttons">
        <h5 class="theme-label"></h5>
        <input class="themeSwitch" type="checkbox" id="switch" name="theme" />
        <label class="toggle" for="switch"></label>
        <label class="switch" for="switch"></label>
      </div>
    </div>
    <div class="burger"></div>
  </div>
</header>

您的第二个事件侦听器永远不会被添加,因为在函数调用时 .nav_links 没有 class .nav_active。因此,您必须将 if (nav.classList.contains("nav_active")) 移动到该侦听器的处理函数中。

工作示例:
(为了演示,我在活动时将背景更改为绿色)

"use strict";

var burger = document.querySelector('.burger');
var nav = document.querySelector('.nav_links');

var navSlide = function() {
  burger.addEventListener('click', function() {
    nav.classList.toggle('nav_active');
    console.log("Clicked on Burger");
  });
  window.addEventListener('click', function(e) {   // i exchanged
    if (nav.classList.contains("nav_active")) {    // these 2 lines
      if (nav.contains(e.target)) {
        console.log("Clicked in Box");
      }
      else {
        console.log("Clicked outside Box");
      }
    }                                              // and
  });                                              // these
};

navSlide();
.nav_home,
.nav_links,
.nav_buttons,
.nav_list {
  display: inline-block;
  vertical-align: middle;
}

.burger {
  width: 2.4rem;
  height: 2.4rem;
  margin: auto 0;
  cursor: pointer;
  background: black;
}

.nav_list a:hover {
  text-decoration: line-through !important;
}

.nav_links {
  display: block;
  z-index: 0;
  position: absolute;
  right: 0rem;
  width: 80%;
  margin-right: 0.1rem;
  border-left: 0.1rem solid;
  background: red;
}

.nav_item {
  display: block;
}

.nav_list {
  display: block;
  a {
    display: block;
  }
  span {
    display: none;
  }
}

.nav_active {
  display: inline-block;
  background-color: green;
}
<header id="header">
  <div class="header container">

    <div class="nav_links">
      <h5 class="nav_list">
        <span class="noselect">⁄</span>
      </h5>

      <div class="nav_buttons">
        <h5 class="theme-label"></h5>
        <input class="themeSwitch" type="checkbox" id="switch" name="theme" />
        <label class="toggle" for="switch"></label>
        <label class="switch" for="switch"></label>
      </div>
    </div>

    <div class="burger"></div>
  </div>

</header>


但我认为当您只想切换菜单时,您可以简单地使用一个事件侦听器(及其处理程序)进行所有操作。因此,您只需处理两种情况:点击是在 burger 上还是在 nav(和汉堡包)之外。第三种情况(最后一个else)只是为了演示。

工作示例:
(我省略了 navSlide() 函数)

"use strict";

var burger = document.querySelector('.burger');
var nav = document.querySelector('.nav_links');

window.addEventListener('click', function(e) {
  if (e.target.classList.contains('burger')) {
    nav.classList.toggle('nav_active');
    console.log("Clicked on Burger");
  }
  else if (!nav.contains(e.target)) {
    nav.classList.remove('nav_active');
    console.log("Clicked outside Box");
  }
  else {
    console.log("Clicked in Box");
  }
});
.nav_home,
.nav_links,
.nav_buttons,
.nav_list {
  display: inline-block;
  vertical-align: middle;
}

.burger {
  width: 2.4rem;
  height: 2.4rem;
  margin: auto 0;
  cursor: pointer;
  background: black;
}

.nav_list a:hover {
  text-decoration: line-through !important;
}

.nav_links {
  display: block;
  z-index: 0;
  position: absolute;
  right: 0rem;
  width: 80%;
  margin-right: 0.1rem;
  border-left: 0.1rem solid;
  background: red;
}

.nav_item {
  display: block;
}

.nav_list {
  display: block;
  a {
    display: block;
  }
  span {
    display: none;
  }
}

.nav_links.nav_active {
  display: inline-block;
  background-color: green;
}
<header id="header">
  <div class="header container">

    <div class="nav_links">
      <h5 class="nav_list">
        <span class="noselect">⁄</span>
      </h5>

      <div class="nav_buttons">
        <h5 class="theme-label"></h5>
        <input class="themeSwitch" type="checkbox" id="switch" name="theme" />
        <label class="toggle" for="switch"></label>
        <label class="switch" for="switch"></label>
      </div>
    </div>

    <div class="burger"></div>
  </div>

</header>


如果您希望仅在菜单打开 (nav.classList.contains("nav_active")) 时添加第二个事件侦听器,否则将其删除,则必须将其嵌套到第一个侦听器的处理程序(匿名函数)中。您必须将第二个处理程序定义为单独的函数(此处 checkClickLocation()),因为 removeEventListener() 需要函数引用(此处 checkClickLocation)作为参数来停止它。

工作示例:

"use strict";

var burger = document.querySelector('.burger');
var nav = document.querySelector('.nav_links');

function checkClickLocation(e) {
  if (!nav.contains(e.target)) {
    nav.classList.remove('nav_active');
    window.removeEventListener('click', checkClickLocation);
    console.log("Clicked outside Box");
  }
  else {
    console.log("Clicked in Box");
  }
}

burger.addEventListener('click', function(e) {
  e.stopPropagation()
  nav.classList.toggle('nav_active');
  if (nav.classList.contains("nav_active")) {
    window.addEventListener('click', checkClickLocation);
  }
  else {
    window.removeEventListener('click', checkClickLocation);
  }
  console.log("Clicked on Burger");
});
.nav_home,
.nav_links,
.nav_buttons,
.nav_list {
  display: inline-block;
  vertical-align: middle;
}

.burger {
  width: 2.4rem;
  height: 2.4rem;
  margin: auto 0;
  cursor: pointer;
  background: black;
}

.nav_list a:hover {
  text-decoration: line-through !important;
}

.nav_links {
  display: block;
  z-index: 0;
  position: absolute;
  right: 0rem;
  width: 80%;
  margin-right: 0.1rem;
  border-left: 0.1rem solid;
  background: red;
}

.nav_item {
  display: block;
}

.nav_list {
  display: block;
  a {
    display: block;
  }
  span {
    display: none;
  }
}

.nav_active {
  display: inline-block;
  background-color: green;
}
<header id="header">
  <div class="header container">

    <div class="nav_links">
      <h5 class="nav_list">
        <span class="noselect">⁄</span>
      </h5>

      <div class="nav_buttons">
        <h5 class="theme-label"></h5>
        <input class="themeSwitch" type="checkbox" id="switch" name="theme" />
        <label class="toggle" for="switch"></label>
        <label class="switch" for="switch"></label>
      </div>
    </div>

    <div class="burger"></div>
  </div>

</header>