简体   繁体   English

如何在切换下拉菜单上添加互斥性

[英]How to add mutually exclusivity on toggling dropdown menu

I have a menu with dropdown submenus.我有一个带有下拉子菜单的菜单。 I'm trying to close an item when clicking on another, so that I don't have multiple items open at the same time.我试图在单击另一个项目时关闭一个项目,这样我就不会同时打开多个项目。 In a previous question: How to Apply .nextElementSibling to the next item of a dropdown menu a user suggested that I take a look at the function called mutually exclusivity.在上一个问题中: How to Apply .nextElementSibling to the next item of a dropdown menu ,用户建议我看一下名为互斥性的函数。 How can I add it to my menu?如何将其添加到我的菜单中?

 var dropdownBtn = document.querySelectorAll('.menu-btn'); dropdownBtn.forEach(btn => btn.addEventListener('click', function() { var menuContent = this.nextElementSibling; menuContent.classList.toggle("show"); }));
 .menu-btn { background: #e0e0e0; padding: 10px; margin: 5px 0px 0px 0px; } .menu-btn:hover { background: #000; color: #fff; } .drop_container { display: none; background-color: #017575; transition: 0.3s; opacity: 0; } .drop_container.show { display: contents; visibility: visible; opacity: 1; } .drop_container > .item { display: flex; flex-direction: column; margin-left: 10px; padding: 10px 0px 0px 0px; }
 <div class="dropdown-menu"> <div class="menu-btn">One</div> <div class="drop_container"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> <div class="menu-btn">Two</div> <div class="drop_container"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> </div>

Store previously clicked menu in a variable, and clear it's class if another menu was clicked将先前单击的菜单存储在变量中,如果单击另一个菜单,则清除它的类

 var dropdownBtn = document.querySelectorAll('.menu-btn'), lastOpened = null; dropdownBtn.forEach(btn => btn.addEventListener('click', function() { var menuContent = this.nextElementSibling; menuContent.classList.toggle("show"); if (lastOpened && lastOpened !== menuContent) lastOpened.classList.remove("show"); lastOpened = menuContent; }));
 .menu-btn { background: #e0e0e0; padding: 10px; margin: 5px 0px 0px 0px; } .menu-btn:hover { background: #000; color: #fff; } .drop_container { display: none; background-color: #017575; transition: 0.3s; opacity: 0; } .drop_container.show { display: contents; visibility: visible; opacity: 1; } .drop_container > .item { display: flex; flex-direction: column; margin-left: 10px; padding: 10px 0px 0px 0px; }
 <div class="dropdown-menu"> <div class="menu-btn">One</div> <div class="drop_container"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> <div class="menu-btn">Two</div> <div class="drop_container"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> </div>

You could add a function that closes all menu's except the one you pass into it:您可以添加一个关闭所有菜单的功能,除了您传递给它的菜单:

 var dropdownBtn = document.querySelectorAll('.menu-btn'); dropdownBtn.forEach(btn => btn.addEventListener('click', function() { var menuContent = this.nextElementSibling; closeMenusExcept(menuContent); menuContent.classList.toggle("show"); })); function closeMenusExcept(menuContent) { dropdownBtn.forEach((element) => { if (menuContent !== element.nextElementSibling) { element.nextElementSibling.classList.remove("show"); } }) }
 .menu-btn { background: #e0e0e0; padding: 10px; margin: 5px 0px 0px 0px; } .menu-btn:hover { background: #000; color: #fff; } .drop_container { display: none; background-color: #017575; transition: 0.3s; opacity: 0; } .drop_container.show { display: contents; visibility: visible; opacity: 1; } .drop_container>.item { display: flex; flex-direction: column; margin-left: 10px; padding: 10px 0px 0px 0px; }
 <div class="dropdown-menu"> <div class="menu-btn">One</div> <div class="drop_container"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> <div class="menu-btn">Two</div> <div class="drop_container"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> </div>

Note I changed the class names so they easier to type and read.请注意,我更改了类名,以便它们更易于键入和阅读。

We'll use the programming paradigm call event delegation.我们将使用编程范式调用事件委托。 Bind event to an ancestor tag (a tag that holds all of the tags you want to control)将事件绑定到祖先标签(包含您要控制的所有标签的标签)

Figure I图一

const menu = document.querySelector(".dropdown"); 
menu.addEventListener('click', //...

Next, design an event handler that only reacts when the right tags are clicked接下来,设计一个事件处理程序,仅在单击正确的标签时做出反应

Figure II图二

//...
  function(event) {
   // This is the tag the user clicked 
   const clicked = event.target;
   // Find .show 
   const current = document.querySelector('.show');
   // See if the clicked tag has .show class
   let state = clicked.matches('.show');
   // Only react if the clicked tag has .btn class
   if (clicked.matches('.btn')) {//...

Note: The .show class is now assigned to the .btn .注意: .show类现在分配给.btn See Figure IV见图四

Figure III图三

//...
      // if there already is a .show    
      if (current) {
        // remove .show
        current.classList.remove('show');
      }
      // if the clicked tag did not have .show previously...
      if (!state) {
        // ...add .show to it
        clicked.classList.add("show");
      }
    }
  });

In CSS this ruleset uses the adjacent sibling combinator which is equivalent to .nextElementSibling在 CSS 中,此规则集使用相邻的兄弟组合子,它等价于.nextElementSibling

Figure IV图四

/* .btn.show + .list <=that's the next sibling */
.show+.list {
  display: block;
} 

Removed visibility and opacity since original state is display:none which is a switch that inhibits any sort of transition (also removed).删除了visibilityopacity ,因为原始状态为display:none ,这是一个禁止任何类型transition的开关(也已删除)。 The display: content was changed to display: block . display: content更改为display: block display: content doesn't have any standard behavior, when applied, the .item s were black and white, but once replaced their original green returned. display: content没有任何标准行为,应用时, .item是黑白的,但一旦替换了原来的绿色,就会返回。 As a general rule dealing with CSS is if you don't see it being used in the examples, don't use it because there's probably a good reason why it isn't being used.作为处理 CSS 的一般规则,如果您在示例中没有看到它,请不要使用它,因为可能有充分的理由不使用它。

With this setup you never have to worry about how many button/items you have as long as it is inside the ancestor tag.使用此设置,您不必担心有多少按钮/项目,只要它位于祖先标签内即可。 Also, if you add any button/items dynamically, they do not need to be bound to the event.此外,如果您动态添加任何按钮/项目,它们不需要绑定到事件。 All you'll ever need is one event listener for each event you want to listen for.您只需要一个事件侦听器来处理您想要侦听的每个事件。

 const menu = document.querySelector(".dropdown"); const btns = document.querySelectorAll('.btn'); menu.addEventListener('click', function(event) { const clicked = event.target; const current = document.querySelector('.show'); let state = clicked.matches('.show'); if (clicked.matches('.btn')) { if (current) { current.classList.remove('show'); } if (!state) { clicked.classList.add("show"); } } });
 .btn { background: #e0e0e0; padding: 10px; margin: 5px 0px 0px 0px; } .btn:hover { background: #000; color: #fff; } .list { display: none; background-color: #017575; } .show+.list { display: block; } .list>.item { display: flex; flex-direction: column; margin-left: 10px; padding: 10px 0px 0px 0px; }
 <div class="dropdown"> <div class="btn">One</div> <div class="list"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> <div class="btn">Two</div> <div class="list"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> <div class="btn">Three</div> <div class="list"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> </div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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