如何在切换下拉菜单上添加互斥性
How to add mutually exclusivity on toggling dropdown 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>
将之前单击的菜单存储在一个变量中,如果单击了另一个菜单,则将其清除 class
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>
您可以添加一个功能来关闭除您传入的菜单之外的所有菜单:
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>
备注
我更改了 class 名称,以便于输入和阅读。
我们将使用编程范式调用事件委托。
将事件绑定到祖先标签(一个包含您要控制的所有标签的标签)
图一
const menu = document.querySelector(".dropdown");
menu.addEventListener('click', //...
接下来,设计一个事件处理程序,仅在单击正确的标签时做出反应
图二
//...
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')) {//...
注意: .show
class 现在分配给 .btn
。见图四
图三
//...
// 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");
}
}
});
在 CSS 中,此规则集使用等效于 .nextElementSibling
的相邻兄弟组合器
图四
/* .btn.show + .list <=that's the next sibling */
.show+.list {
display: block;
}
删除了 visibility
和 opacity
,因为原始状态是 display:none
,这是一个禁止任何类型的 transition
的开关(也已删除)。 display: content
已更改为 display: block
。 display: content
没有任何标准行为,应用时,.item
是黑白的,但一旦替换它们原来的绿色就会返回。作为处理 CSS 的一般规则,如果您没有在示例中看到它被使用,请不要使用它,因为可能有充分的理由不使用它。
使用此设置,只要它在祖先标记内,您就不必担心有多少 button/items。此外,如果您动态添加任何 button/items,则它们不需要绑定到事件。您所需要的只是为您要侦听的每个事件设置一个事件侦听器。
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>
我有一个带有下拉子菜单的菜单。我试图在点击另一个项目时关闭一个项目,这样我就不会同时打开多个项目。上一个问题:
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>
将之前单击的菜单存储在一个变量中,如果单击了另一个菜单,则将其清除 class
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>
您可以添加一个功能来关闭除您传入的菜单之外的所有菜单:
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>
备注 我更改了 class 名称,以便于输入和阅读。
我们将使用编程范式调用事件委托。 将事件绑定到祖先标签(一个包含您要控制的所有标签的标签)
图一
const menu = document.querySelector(".dropdown");
menu.addEventListener('click', //...
接下来,设计一个事件处理程序,仅在单击正确的标签时做出反应
图二
//...
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')) {//...
注意: .show
class 现在分配给 .btn
。见图四
图三
//...
// 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");
}
}
});
在 CSS 中,此规则集使用等效于 .nextElementSibling
图四
/* .btn.show + .list <=that's the next sibling */
.show+.list {
display: block;
}
删除了 visibility
和 opacity
,因为原始状态是 display:none
,这是一个禁止任何类型的 transition
的开关(也已删除)。 display: content
已更改为 display: block
。 display: content
没有任何标准行为,应用时,.item
是黑白的,但一旦替换它们原来的绿色就会返回。作为处理 CSS 的一般规则,如果您没有在示例中看到它被使用,请不要使用它,因为可能有充分的理由不使用它。
使用此设置,只要它在祖先标记内,您就不必担心有多少 button/items。此外,如果您动态添加任何 button/items,则它们不需要绑定到事件。您所需要的只是为您要侦听的每个事件设置一个事件侦听器。
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>