Закройте боковую панель, когда я нажимаю за ее пределами

#javascript #html #css #menu

Вопрос:

Я пытаюсь закрыть боковую панель, когда нажимаю за ее пределами. Я добавил условие, чтобы закрывать его только в том случае, если он открыт ( nav_active ), но мне чего-то не хватает. Ожидаемое поведение будет заключаться в отображении предупреждения, когда я нажимаю внутри или снаружи красного поля.

редактировать после решения я только что понял, что первый щелчок будет снаружи, поэтому, когда я удалю активный класс, ползунок никогда не будет отображаться

 "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> 

Ответ №1:

Ваш второй прослушиватель событий никогда не добавляется, потому что вызов функции at .nav_links не имеет класса .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> 

Комментарии:

1. Хотел бы знать, зачем помещать addEventListener коды в сторону функции, а затем вызывать ее. Мы можем выставить его на улицу без какой-либо функции, я думаю?

2. Да, я тоже хотел бы это знать. Может быть, @smugdessert знает…

3. я также хотел бы знать, что

4. единственное, что я хочу спросить, это как у меня может быть window.addEventListener триггер только при nav_active добавлении. Я не хочу всегда проверять, где я нажимаю, если знаю, что ползунок закрыт.

5. спасибо, я только что начал изучать JS и ценю вашу помощь

Ответ №2:

Вам просто нужно было переместить код в свой прослушиватель — и я переформатировал способ, которым вы назначаете переменную функции. Наконец, я удалил прослушиватель 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> 

Комментарии:

1. Как только вы добавили прослушиватель событий, он останется добавленным даже после того, как список классов переключения удалит nav_active класс. таким образом, этот код window.addEventListener('click' всегда будет оставаться активным. Я думаю, это неправильное решение?

2. Отличная мысль и спасибо @RajdeepDebnath — код обновлен