Problem when closing menu

Asked

Viewed 31 times

0

Good morning guys, all right with you?

I have a problem that I can not find the solution at all (I am layman with JS yet). The thing is, I have an Offcanvas menu that opens when I click on the burger icon, I can make it open and close, but I wish when I click off the menu it would also close, but I’m not able to do that, when I think of a logic, stop opening and closing the menu. Follow the JS code

const open_menu = document.getElementById('js-open-button');
const close_menu = document.getElementById('js-close-button');

open_menu.addEventListener('click', OnCanvas );
close_menu.addEventListener( 'click', OffCanvas);
var abriu = false;

// Ao clicar no ícone de hambúrguer , abre o menu
function OnCanvas() {
    if(!abriu) {
        document.body.classList.add('show-menu');
        abriu = true;
    }
}

// Ao clicar no X fecha o menu
function OffCanvas() {
    if(abriu) {
        document.body.classList.remove('show-menu');
        abriu = false;
    }
}

The HTML I’m using

<!-- Off Canvas Menu -->
<div class="offCanvas">
  <nav class="menu">
    <div class="icon-list">
      <!-- Form Search -->
      <form class="d-flex">
        <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
        <button class="btn search-button-icon" type="submit"><i class="fas fa-search"></i></button>
      </form>
      <!-- End Form Search -->

      <!-- Navbar -->
      <ul class="navbar-nav w-100 justify-content-end">
        <li class="nav-item">
          <a href="#" class="nav-link active" aria-current="page"><i class="fas fa-home"></i> INÍCIO</a>
        </li>
      </ul>
      <!-- End Navbar -->
    </div>
  </nav>
  <button class="close-button" id="js-close-button">Close Menu</button>
</div>
<!-- End Off Canvas Menu -->
<div class="content-wrap">
  <div class="js-content">
    <header>
      <!-- Head Navbar -->
      <nav class="navbar navbar-expand-lg bg-header" id="navbarNav">
        <div class="container-fluid">

          <!-- Toggle Button -->
          <button class="menu-button d-block d-xl-none d-lg-none" id="js-open-button" type="button" >
            <span><i class="fas fa-bars"></i></span>
          </button>
          <!-- Toggle Button End -->
        
          <!-- Logo -->
          <a class="navbar-brand" href="#">
            <img class="img-fluid" width="130" src="./assets/images/logo_imperial.svg" alt="Logo Imperial">
          </a>
          <!-- End Logo -->

          <div class="collapse navbar-collapse">
            <!-- Navbar -->
            <ul class="navbar-nav w-100 justify-content-end">
              <li class="nav-item">
                <a href="#" class="nav-link active" aria-current="page">INÍCIO</a>
              </li>
            </ul>
            <!-- End Navbar -->

            <!-- Form Search -->
            <form class="d-flex" id="search-form">
              <input class="form-control me-2" type="search" placeholder="Pesquisar..." aria-label="Pesquisar">
              <button class="btn search-button-icon" type="submit"><i class="fas fa-search"></i></button>
            </form>
            <!-- End Form Search -->
          </div>
        </div>
      </nav>
      <!-- End Head Navbar -->
    </header>
  </div>
</div>

Thanks in advance :)

1 answer

0


Basically you have to register the click Event on the body of the document and check if the clicked element is inside the offcanvas. This translates into a recursive function isElementInOffCanvas verifying whether a given element (and its parent elements) has the class offCanvas.

I simplified your logic a little bit, namely removing the flag abriu and using classList.toggle to control menu visibility.

Please check the following code.

document.body.addEventListener('click', function(e) { bodyClick(e); });
document.getElementById('js-open-button').addEventListener('click', toggleOffCanvas);
document.getElementById('js-close-button').addEventListener('click', toggleOffCanvas);

function bodyClick(e) {
  if (e.target.classList.contains('open-button')) return;

  if (!isElementInOffCanvas(e.target)) {
    document.body.classList.remove('show-menu');
  }
}

function isElementInOffCanvas(element) {
  if (element.classList && element.classList.contains('offCanvas')) return true;

  return (element.parentNode && isElementInOffCanvas(element.parentNode)) || false;
}

function toggleOffCanvas() {
  document.body.classList.toggle('show-menu');
}
.container {
  position: relative;
  padding: 10px;
  min-height: 300px;
  background-color: teal;
}

.offCanvas {
  position: absolute;
  top: 10px;
  bottom: 10px;
  left: -100%;
  padding: 10px;
  background-color: orange;
  width: 216px;
  transition: all ease .5s;
}

.show-menu .offCanvas {
  left: 10px;
}
<div class="container">
  <button class="open-button" id="js-open-button">Open Menu</button>

  <div class="offCanvas">
    <nav class="menu">
      <div class="icon-list">
        <form class="d-flex">
          <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
          <button class="btn search-button-icon" type="submit">Search</button>
        </form>
        <ul class="navbar-nav w-100 justify-content-end">
          <li class="nav-item">
            <a href="#" class="nav-link active" aria-current="page">Início</a>
          </li>
        </ul>
      </div>
    </nav>
    <button class="close-button" id="js-close-button">Close Menu</button>
  </div>
</div>

  • Top bro, thanks so much!! Just happening a strange problem, on my button to open the menu, I put an icon of Font Awsome, only if I put the class "open-button" on the button, clicking on the icon does not work and vice versa and if I put in both, the icon does not work. You could tell me what’s going on?

  • In the beginning I would say to put in both. It is only a class for control in javascript, it is not intended to associate any css.

  • Just press "check" at the beginning of your question. Here explains better how to do it.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.