当单击另一个菜单项的按钮(第一个 'cousin')时关闭一个菜单项的子菜单 Javascript 而没有 jQuery

Close submenus of one menu item when another menu item's button ('cousin' of first) is clicked with Javascript and no jQuery

我有一个 clickable/tappable 菜单(它可以有无限级)纯 html、css(没有 Bootstrap)、香草 javascript 和否 jQuery.

当我单击链接到带有子菜单的菜单项的按钮时,它会打开子菜单,当我再次单击该按钮时,它会关闭子菜单。一切都很好。

但是,我无法弄清楚的是当我单击另一个顶级主项目的按钮时如何关闭已经打开的子菜单(我称之为元素的 'cousin':元素的 parent's sibling's child) 打开它的子​​菜单。所以我最终得到两个或多个并排打开且重叠的子菜单。

我在这里尝试了一个版本的答案: 这似乎与我正在尝试做的最接近,但没有成功。

这是我的片段:

/// this script opens the sub-menu when the li button is clicked
document.getElementById("menucontent").addEventListener("click", openSubMenu);
function openSubMenu(event){
    if(event.target.type === "button"){
    event.target.nextElementSibling.classList.toggle("hidden");
    event.target.classList.add("clicked");
    event.target.classList.remove("not-clicked");
    }
}
// this script switches the triangle direction when the button is clicked
document.getElementById("menucontent").addEventListener("click", triangle);
function triangle(event){
    if(event.target.type === "button"){
    event.target.classList.toggle("triangle");
    }
}
// this script closes the submenus when clicking anywhere outside the menu and reverts the triangle to pointing down
document.getElementById("mainbody").addEventListener("click", closeMenu);
function closeMenu(event) {
    if(event.target.type != "button") {
    var level1 = document.getElementsByClassName("level-1");
    var level2 = document.getElementsByClassName("level-2");
    var btnlevel1 = document.getElementsByClassName("btn-level-1");
    var btnlevel2 = document.getElementsByClassName("btn-level-2");
        for (var i = 0; i < level1.length; i++) {
        level1[i].classList.add("hidden"); }
        for (var i = 0; i < level2.length; i++) {
        level2[i].classList.add("hidden"); }
        for (var i = 0; i < btnlevel1.length; i++){
        btnlevel1[i].classList.remove("triangle");
        btnlevel1[i].classList.remove("clicked");}
        for (var i = 0; i < btnlevel2.length; i++) {
        btnlevel2[i].classList.remove("triangle");
        btnlevel2[i].classList.remove("clicked");}
    }
}
document.getElementById("mainbody").addEventListener("click", addClass);
function addClass(event) {
// the click is triggered outside the menu
    if(event.target.type != 'button') {
// these are top level buttons only
    var buttons = document.querySelectorAll('.btn-level-1.clicked');
        for (var i = 0; i < buttons.length; i++) {
        buttons[i].classList.add('not-clicked');
        buttons[i].classList.remove('clicked'); }
    }
}
.outer {
 border: 2px solid gray;
 margin: 1rem;
 padding: 1rem; 
}
.stickymenuwrapper {
 background-color: #fff;
 transition-duration: 0s;
 padding: 0;
 margin: 0 auto;
 z-index: 995;
 }
.scrabble-menu .hidden {
 display: none;
}
.scrabble-menu .navbar > li {
 display: inline-block;
}
.scrabble-menu ul {
 list-style: none;
 margin-bottom: 0;
 white-space: nowrap;
 padding: 0;
}
.scrabble-menu ul.navbar {
 background-color: pink;
 padding: 0 1rem;
}
.scrabble-menu li ul {
 position: absolute;
 top: 100%;
 background-color: pink;
 border: 1px solid red;
 padding: 0 12px 0 12px;
}
.scrabble-menu ul.level-2,
.scrabble-menu ul.level-3 {
 background-color: yellow;
 top: 0%;
 left: 100%;
 padding-bottom: 0.5rem;
 }
.scrabble-menu ul.level-3 {
 background-color: orange;
 } 
.scrabble-menu li.active > a {
 text-decoration: underline;
}
.scrabble-menu a.separator:hover {
 text-decoration: none;
 }
.scrabble-menu button,
.scrabble-menu button:focus {
 background: none;
 border: none;
 height: 2.5rem;
 width: 1.75rem;
 outline:none;
 padding: 0;
}
.scrabble-menu li {
 position: relative;
 display: flex;
 margin: 0;
 padding: 0;
 line-height: 1.5rem;
}
.scrabble-menu .navbar > li > a {
 padding: 0.5rem 0 0.5rem 0.5rem;
 margin-left: 1rem;
}
.scrabble-menu .navbar > li:first-child > a {
 padding: 0.5rem 0.5rem 0.5rem 0;
 margin-left: 0;
}
.scrabble-menu li button:after {
 font-size: 0.8rem;
 position: relative;
 right: -3px;
 top: 0;
}  
.scrabble-menu ul.level-1 > li a {
 padding-top: 0.5rem;
}
.scrabble-menu li button[class^="btn-level"]:after {
 content: "B6";
 cursor: pointer;
}
.scrabble-menu .triangle{
}
.scrabble-menu li button[class^="btn-level"].triangle:after {
 content: "C0";
}
.scrabble-menu li button.btn-level-1:after {
 content: "BC";
}
.scrabble-menu li button.btn-level-1.triangle:after {
 content: "B2";
}
<div id="mainbody" class="outer">This is a menu that works with pure html, css and vanilla Javascript. There is no jQuery.<br>There is JS to close the menu when clicking outside the menu and to close each open submenu when its parent's button is clicked. The arrows (including for submenus) switch accordingly.
<div class="row sticky-main-menu">
    <div id="stickymenuwrapper" class="col stickymenuwrapper scrabble-menu">
    <ul id="menucontent" class="navbar">
<li class="item-101 single current active">
<a href="/" class="one">HOME</a></li>
<li class="item-122 single divider deeper parent">
<a class="two">TEST TWO</a>
<button class="btn-level-1" type="button"></button>
<ul id="drop-122" class="hidden level-1">
    <li class="item-121 single">
    <a href="/" class="">Test level 2</a>
    </li>
</ul>
</li>
<li class="item-103 single deeper parent">
<a href="/" class="two">ABOUT</a>
<button class="btn-level-1" type="button"></button>
<ul class="level-1 hidden">
    <li class="item-104 single">
    <a href="/" class="">About us</a>
    </li>
    <li class="item-104 single">
    <a href="/" class="">More</a>
    </li>
</ul>
</li>
</ul>
</div>
</div>
</div>

谢谢。

我稍微精简了代码,现在从包装器中委托

function openLowerMenu(e) {
  const tgt = e.target;
  e.currentTarget.nextElementSibling.classList.toggle('test1', tgt.type === "button");
  e.currentTarget.nextElementSibling.classList.add('test2', tgt.type !== "button");
}

document.getElementById("stickymenuwrapper").addEventListener("click", function(e) {
  const tgt = e.target;
  if (tgt.type==="button") {
    const level = tgt.className.replace(/[^\d]/g,"");
    [...document.querySelectorAll('ul.level-'+level)].forEach(ul => ul.classList.add("hidden"));
    const show = tgt.classList.contains("triangle")
    tgt.nextElementSibling.classList.toggle("hidden",!show); 
    tgt.classList.toggle("triangle",!show);
  }
});
.row {
  margin: 0 1rem;
}

.outer {
  border: 2px solid gray;
  margin: 1rem;
  padding: 1rem;
}

.sticky-main-menu {
  z-index: 9999;
}

.stickymenuwrapper {
  background-color: #fff;
  transition-duration: 0s;
  padding: 0;
  margin: 0 auto;
  z-index: 995;
}

.scrabble-menu .hidden {
  display: none;
}

.scrabble-menu .navbar>li {
  display: inline-block;
}

.scrabble-menu ul {
  list-style: none;
  margin-bottom: 0;
  white-space: nowrap;
  padding: 0;
}

.scrabble-menu ul.navbar {
  background-color: pink;
  padding: 0 1rem;
  /* text-align: center;*/
}

.scrabble-menu li ul {
  position: absolute;
  top: 100%;
  background-color: pink;
  border: 1px solid red;
  padding: 0 12px 0 12px;
}

.scrabble-menu ul.level-2,
.scrabble-menu ul.level-3 {
  background-color: yellow;
  top: 0%;
  left: 100%;
  padding-bottom: 0.5rem;
}

.scrabble-menu ul.level-3 {
  background-color: orange;
}

.scrabble-menu li.active>a {
  text-decoration: underline;
}

.scrabble-menu a.separator:hover {
  text-decoration: none;
}

.scrabble-menu button,
.scrabble-menu button:focus {
  background: none;
  border: none;
  height: 2.5rem;
  width: 1.75rem;
  outline: none;
  padding: 0;
}

.scrabble-menu li {
  position: relative;
  display: flex;
  margin: 0;
  padding: 0;
  line-height: 1.5rem;
}

.scrabble-menu .navbar>li>a {
  padding: 0.5rem 0 0.5rem 0.5rem;
  margin-left: 1rem;
}

.scrabble-menu .navbar>li:first-child>a {
  padding: 0.5rem 0.5rem 0.5rem 0;
  margin-left: 0;
}


/* separator line code here */

.scrabble-menu li button:after {
  font-size: 0.8rem;
  position: relative;
  right: -3px;
  top: 0;
}

.scrabble-menu ul.level-1>li a {
  padding-top: 0.5rem;
}

.scrabble-menu li button[class^="btn-level"]:after {
  content: "B6";
  cursor: pointer;
}

.scrabble-menu li button[class^="btn-level"].triangle:after {
  content: "C0";
}

.scrabble-menu li button.btn-level-1:after {
  content: "B2";
}

.scrabble-menu li button.btn-level-1.triangle:after {
  content: "BC";
}

.scrabble-menu li button.btn-level-1.triangle2:after {
  content: "BC";
}

.scrabble-menu .clicked {}

.scrabble-menu li button[class^="btn-level"].not-clicked:after {
  content: "B0";
  cursor: pointer;
}

.scrabble-menu li button.btn-level-1.not-clicked::after {
  content: "BC";
}
<div class="row sticky-main-menu">
  <div id="stickymenuwrapper" class="col stickymenuwrapper scrabble-menu">
    <ul id="menucontent" class="scrabblemenu navbar">
      <li class="item-122 single divider deeper parent">
        <a class="two">ITEM ONE</a>
        <button class="btn-level-1 triangle" type="button"></button>
        <ul id="drop-122" class="hidden level-1">
          <li class="item-121 single">
            <a href="/" class="">Item One level 2</a>
          </li>
          <li class="item-134 single deeper parent">
            <a class="nav-header two">Item One level 2 menu heading</a>
            <button class="btn-level-2" type="button"></button>
            <ul id="drop-134" class="level-2 hidden">
              <li class="item-135 single">
                <a href="/" class="">Article under menu heading</a>
              </li>
            </ul>
          </li>
        </ul>
      </li>
      <li class="item-122 single divider deeper parent">
        <a class="two">ITEM TWO</a>
        <button class="btn-level-1 triangle" type="button"></button>
        <ul id="drop-122" class="hidden level-1">
          <li class="item-121 single">
            <a href="/" class="">Item Two level 2</a>
          </li>
          <li class="item-134 single deeper parent">
            <a class="nav-header two">Item Two level 2 menu heading</a>
            <button class="btn-level-2" type="button"></button>
            <ul id="drop-134" class="level-2 hidden">
              <li class="item-135 single">
                <a href="/" class="">Article under menu heading</a>
              </li>
            </ul>
          </li>
        </ul>
      </li>
      <li class="item-103 single deeper parent">
        <a href="/" class="two">ITEM THREE WITH LINK</a>
        <button class="btn-level-1 triangle" type="button"></button>
        <ul class="not-separator level-1 hidden">
          <li class="item-104 single">
            <a href="/" class="">Article under Item Three</a>
          </li>
          <li class="">
            <a class="two separator">Item Three Level 2 separator</a>
            <button class="btn-level-2" type="button"></button>
            <ul id="drop-107" class="level-2 hidden">
              <li class="item-108 single">
                <a href="/" class="">Lower article</a>
              </li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </div>
</div>