简体   繁体   中英

How to use toggle function in JavaScript?

So I am running into a couple of problems when I try to use JavaScript to toggle between classes on click.

What is going on.. Also when I run it on my localhost it runs but only on the first link. not on the second. I tried recreating the same problem but here it becomes even more a mess..

Now for some reason if I use this code even in the snippet, when you click the event happends, then dissapears completely.

 var pill = document.querySelector(".navpill"); var sub = document.querySelector(".submenu"); pill.onclick = () => { sub.classList.toggle("collapse"); }
 .mainmenu { background-color: #1f1f1f; }.navpill { padding: 15px; }.navpill a { text-decoration: none; color: white; }.submenu { display: none; }.submenu.collapse { display: block; }
 <div> <ul class="mainmenu"> <li class="navpill"><a href="">Link collapse 1</a> <ul class="submenu"> <li class="navpill"><a href="">sub Link 1</a></li> <li class="navpill"><a href="">sub Link 1</a></li> <li class="navpill"><a href="">sub Link 1</a></li> <li class="navpill"><a href="">sub Link 1</a></li> </ul> </li> <li class="navpill"><a href="">Link collapse 2</a> <ul class="submenu"> <li class="navpill"><a href="">sub Link 1</a></li> <li class="navpill"><a href="">sub Link 1</a></li> <li class="navpill"><a href="">sub Link 1</a></li> <li class="navpill"><a href="">sub Link 1</a></li> </ul> </li> <li class="navpill"><a href="">no link</a></li> <li class="navpill"><a href="">no link</a></li> </ul> </div>

href="" makes it try to navigate to another page. Either try href="#" or just don't user hyperlinks if they're not actually intended to be real links. <li class="navpill">sub Link 1</li> ought to be just fine for you I'd expect.

Also, querySelector only selects the first element in the selected set. So it only acts on your first link. You need to use querySelectorAll , loop through the results and add a click to each.

Identifying the specific sublink to act on needs to be done within the click callback, so you can find the one within the menu item which has just been clicked. Also you can't use navpill as the class selector for handling the expand/collapse clicks, as it'll crash if you click on one of the sublinks with that class. So I added a new class for the outer, clickable items.

Demo:

 var pills = document.querySelectorAll(".expand"); pills.forEach(function(pill) { pill.onclick = () => { var sub = pill.querySelector(".submenu"); sub.classList.toggle("collapse"); } });
 .mainmenu { background-color: #1f1f1f; }.navpill { padding: 15px; color: white; }.submenu { display: none; }.submenu.collapse { display: block; }
 <div> <ul class="mainmenu"> <li class="navpill expand">Link collapse 1 <ul class="submenu"> <li class="navpill">sub Link 1</li> <li class="navpill">sub Link 1</li> <li class="navpill">sub Link 1</li> <li class="navpill">sub Link 1</li> </ul> </li> <li class="navpill expand">Link collapse 2 <ul class="submenu"> <li class="navpill">sub Link 1</li> <li class="navpill">sub Link 1</li> <li class="navpill">sub Link 1</li> <li class="navpill">sub Link 1</li> </ul> </li> <li class="navpill">no link</li> <li class="navpill">no link</li> </ul> </div>

By using the same class for all of your nav, both main and sub you will need to change how you are calling your nav.

using QuerySelectorALL and > you can get just the main nav. Then using nextElementSibling you can get the next navigation.

I'm also looking for an already open menu and hiding it.

 var pills = document.querySelectorAll(".mainmenu >.navpill"); pills.forEach((pill) => { pill.onclick = (e) => { sub = e.target.nextElementSibling; open = document.querySelector(".submenu.collapse") if(open) open.classList.remove("collapse"); if(sub) sub.classList.toggle("collapse"); e.preventDefault(); } });
 .mainmenu { background-color: #1f1f1f; }.navpill { padding: 15px; }.navpill a { text-decoration: none; color: white; }.submenu { display: none; }.submenu.collapse { display: block; }
 <div> <ul class="mainmenu"> <li class="navpill"><a href="">Link collapse 1</a> <ul class="submenu"> <li class="navpill"><a href="">sub Link 1</a></li> <li class="navpill"><a href="">sub Link 1</a></li> <li class="navpill"><a href="">sub Link 1</a></li> <li class="navpill"><a href="">sub Link 1</a></li> </ul> </li> <li class="navpill"><a href="">Link collapse 2</a> <ul class="submenu"> <li class="navpill"><a href="">sub Link 1</a></li> <li class="navpill"><a href="">sub Link 1</a></li> <li class="navpill"><a href="">sub Link 1</a></li> <li class="navpill"><a href="">sub Link 1</a></li> </ul> </li> <li class="navpill"><a href="">no link</a></li> <li class="navpill"><a href="">no link</a></li> </ul> </div>

querySelector selects just one element. Use querySelectorAll .

Then to limit the submenu items affected to just the ones under their parent menu item, query from that element as opposed to from the document . You'll also want to limit querySelectorAll to just choose elements with the navpill class which are direct children of the mainmenu class (done using the > symbol between selectors).

let pill = document.querySelectorAll(".mainmenu > .navpill");

pill.forEach ((element) => {
  let sub = element.querySelector(".submenu");
  let mainItem = element.firstChild;
  /* if you want your menu to collapse when clicking a submenu item
   * remove the line above, and on the line below, replace "mainItem"
   * with "element". */
  mainItem.onclick = (e) => {
    if (sub){
      sub.classList.toggle("collapse");
    }
  }
});

Note: Because your submenu items are encompassed in / children of your main menu items (per the selectors originally chosen), clicking on a submenu item will also set off the click event handler for the main menu item above it (the <li> ). If each submenu item has a link, you'll likely not care - but clicking on a submenu item will also collapse the submenu. The comment in the code above explains how to obtain either behavior, defaulting with the option of leaving the submenu open unless explicitly closed by again clicking on the main menu item.

As far as the difference between href="#" vs href="" , as others suggested, you can use <a> for your main menu items which are themselves links, and use something else, for example, <span> to hold your main menu items meant to open a submenu. That way, you don't send users to the top of your page any time they click a main menu item (using href="#" ). You can then change your css for main item entries to the following, so that you get the same cursor behavior for both <a> and <span> :

.navpill span, .navpill a {
  text-decoration: none;
  color: white;
  cursor: pointer;
}

That's a quite understandable way to handle it. In the case, for example, another developer has to one day edit the site, they'd quickly understand your intentions and not get tripped up in e.preventDefault or other relatively obscure code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM