How to interact multiple dropdown menu?

Asked

Viewed 69 times

0

I have two menus, what function to do and how to do, so when open one, close the other? And when clicking outside the close menu also? Thank you!

My code

function menu1() {
    document.getElementById('dropdown').classList.toggle('visivel')
    
  }

  function menu2() {
    document.getElementById('dropdown2').classList.toggle('visivel')
    
  }
.submenu {
    display: none;
}

.visivel {
    display: flex;
}
<!doctype html>
<html lang="en">
  <head>
    <title>Title</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" type="text/css" href="estilo.css">
  </head>
  <body>
      <div>
          <button onclick="menu1()">BOTAO</button>
          <div class="submenu" id="dropdown">
              <div>conteudo1</div>
              <div>conteudo2</div>
              <div>conteudo3</div>
              <div>conteudo4</div>
              <div>conteudo5</div>
          </div>

          <button onclick="menu2()">BOTAO2</button>
          <div class="submenu" id="dropdown2">
              <div>conteudo1</div>
              <div>conteudo2</div>
              <div>conteudo3</div>
              <div>conteudo4</div>
              <div>conteudo5</div>
          </div>
      </div>
      <script type="text/javascript" src="javascript.js"></script>
  </body>
</html>

  • Tried to? function menu1() {&#xA; document.getElementById('dropdown').classList.toggle('visivel'); document.getElementById('dropdown2').classList.toggle("submenu"); &#xA; &#xA; }&#xA;&#xA; function menu2() {&#xA; document.getElementById('dropdown2').classList.toggle('visivel'); document.getElementById("dropdown").classList.toggle("submenu");&#xA; &#xA; }

2 answers

2

You could do a query to select all the other submenus and then remove the class visivel

// busca todos os elementos com a classe submenu, exceto o com ID dropdown2
for (var outroSubmenu of document.querySelectorAll('.submenu:not(#dropdown2)')) {
    outroSubmenu.classList.remove('visivel')
}

document.getElementById('dropdown2').classList.toggle('visivel')

Another improvement would be to create a single function to manipulate all submenus, and take as parameter the id of the clicked element:

function toggleMenu(id) {
    for (var outroSubmenu of document.querySelectorAll(`.submenu:not(#${id})`)) {
        outroSubmenu.classList.remove('visivel')
    }
    document.getElementById(id).classList.toggle('visivel')
}
.submenu {
    display: none;
}

.visivel {
    display: block;
}

button {
    display: block;
    margin-top: 10px
}
<!doctype html>
<html lang="en">
  <head>
    <title>Title</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" type="text/css" href="estilo.css">
  </head>
  <body>
      <div>
          <button onclick="toggleMenu('dropdown')">BOTAO</button>
          <div class="submenu" id="dropdown">
              <div>conteudo1</div>
              <div>conteudo2</div>
              <div>conteudo3</div>
              <div>conteudo4</div>
              <div>conteudo5</div>
          </div>

          <button onclick="toggleMenu('dropdown2')">BOTAO2</button>
          <div class="submenu" id="dropdown2">
              <div>conteudo6</div>
              <div>conteudo7</div>
              <div>conteudo8</div>
              <div>conteudo9</div>
              <div>conteudo10</div>
          </div>
      </div>
      <script type="text/javascript" src="javascript.js"></script>
  </body>
</html>

  • Hey, buddy, how about four menus? Same idea?

  • Yes, how querySelectorAll search all submenus, no matter you have 2 or 100 of them, as long as they have the class submenu, all of them will be "closed".

  • Thank you very much for your explanation!

1


There is a more generic way to do this without having to create a function for each button and use id’s. Just put a class in the buttons to add Events handlers to all. Clicking on the button will fetch the adjacent element (which comes after) with .nextElementSibling.

Also create a Event Handler to the document which will hide all menus when you click out of it or the buttons.

See below for explanatory comments on what the code does:

// pega todos os botões pela classe
const botoes = document.querySelectorAll(".botaomenu");

// cria um evento para o document
document.onclick = function(){
   // percorre todos os menus e remove a classe
   for(let menu of botoes){
      menu.nextElementSibling.classList.remove("visivel");
   }
}

// percorre todos os botões e cria os eventos
for(let menu of botoes){
   menu.onclick = function(e){
      e.stopPropagation(); // impede que o clique atinja o document
      let visivel = document.querySelector(".visivel"); // busca um menu visível
      // se houver um menu visivel, oculta ele desde que não seja o referente ao botão clicado
      if(visivel && visivel != e.target.nextElementSibling) visivel.classList.remove("visivel");
      // altera a classe
      this.nextElementSibling.classList.toggle('visivel');
   }
   // impede que o document seja atinjido ao clica dentro do menu
   menu.nextElementSibling.onclick = function(e){
      e.stopPropagation();
   }
}
.submenu {
    display: none;
}

.visivel {
    display: flex;
}
<button class="botaomenu">BOTAO</button>
<div class="submenu">
   <div>conteudo1</div>
   <div>conteudo2</div>
   <div>conteudo3</div>
   <div>conteudo4</div>
   <div>conteudo5</div>
</div>

<button class="botaomenu">BOTAO2</button>
<div class="submenu">
   <div>conteudo122</div>
   <div>conteudo2</div>
   <div>conteudo32</div>
   <div>conteudo42</div>
   <div>conteudo52</div>
</div>

  • Thank you very much teacher for your explanation! It worked perfect.

Browser other questions tagged

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