对于以下代码:
const allDropdowns = document.querySelectorAll(".main-nav__dropdown");
window.addEventListener("click", (e) => {
[...allDropdowns].forEach((dropdown) => (dropdown.open = false));
});
<details class="main-nav__dropdown">
<summary>First</summary>
<ul>
<li><a href="#">First</a></li>
<li><a href="#">Second</a></li>
<li><a href="#">Third</a></li>
<li><a href="#">Fourth</a></li>
</ul>
</details>
<details class="main-nav__dropdown">
<summary>Second</summary>
<ul>
<li><a href="#">First</a></li>
<li><a href="#">Second</a></li>
</ul>
</details>
为什么每当我单击
summary
本身时下拉菜单都不会关闭?我怎样才能让它工作?
将
click
活动更改为 mousedown
到目前为止一切顺利 🤞
图A
document.addEventListener('mousedown', closeDD);
我认为这是因为事件处理程序将侦听窗口上的所有单击事件,其中包括所有
<summary>
,因此存在冲突。每次点击 <summary>
都会触发两个事件处理程序:
<details>
。<details>
。手风琴的制作方式通常是使用内容框的outside按钮来折叠和展开。对于像
<details>
和 <summary>
这样的嵌套按钮,当您想要添加额外的事件处理程序来执行不同的操作时,单击事件会出现问题。我认为这就是为什么将 "toggle" 事件添加到 HTMLDetailsElement 界面的原因。它在 <details>
打开或关闭后立即触发。
在下面的示例中,有两个事件处理程序:
事件处理程序 | 活动 | 听众 | 目的 |
---|---|---|---|
|
|
|
当用户单击任意位置时,所有 将关闭 |
|
|
全部
|
如果用户单击 ,则会记录其索引,并且一旦所有 都已被 关闭。录制的 如果最初关闭,将会重新打开。 |
除了前面描述的行为之外,作为副作用,还实现了互斥性 - 基本上一次只能打开一个
<details>
。
我忘记添加最重要的修复之一,即
pointer-events
在活动的<summary>
上被禁用,并在<details>
关闭时重新启用。对于我的一生,我无法完全解决点击冲突,因此当 <details>
打开时,看起来像 <summary>
上的点击有效,但实际上是 <details>
对点击做出了反应。
详情已在示例中注释
// Collect all <details> in an array
const allDD = Array.from(document.querySelectorAll("details"));
// Define a flag outside of function
let status = -1;
// Bind document to the mousedown event
document.addEventListener('mousedown', closeDD);
function closeDD(e) {
// Enable pointer-events on each <summary>
allDD.forEach(dd => dd.firstElementChild.style.pointerEvents = 'auto');
// Reference the tag that the user clicked
const active = e.target;
/*
If the tag the user clicked is a <summary> AND it's parent <details>
is [open]...
...Find the index of that <details> and assign it to the status flag
*/
if (active.matches('summary') && !active.parentElement.hasAttribute('open')) {
status = allDD.indexOf(active.parentElement);
}
// Next, close all <details>
allDD.forEach(dd => dd.open = false);
}
// Bind all <details> to the toggle event
allDD.forEach(dd => dd.ontoggle = checkDD);
function checkDD(e) {
// The current <details> tag
const active = e.target;
// Find it's index
let position = allDD.indexOf(active);
/*
If the index matches the flag...
...The <details> opens...
...Disable pointer-events on <summary>
*/
if (status === position) {
active.open = true;
active.firstElementChild.style.pointerEvents = 'none';
}
// Rest flag
status = -1;
}
details {
outline: 5px solid blue;
}
summary {
outline: 3px dashed red;
cursor: pointer;
user-select: none;
}
<details>
<summary>First</summary>
<ul>
<li><a href="https://example.com">First</a></li>
<li><a href="https://example.com">Second</a></li>
</ul>
</details>
<details>
<summary>Second</summary>
<ul>
<li><a href="https://example.com">First</a></li>
<li><a href="https://example.com">Second</a></li>
<li><a href="https://example.com">Third</a></li>
</ul>
</details>
<details>
<summary>Third</summary>
<ul>
<li><a href="https://example.com">First</a></li>
<li><a href="https://example.com">Second</a></li>
<li><a href="https://example.com">Third</a></li>
<li><a href="https://example.com">Fourth</a></li>
</ul>
</details>
请检查下面的代码。
// create array with all elements to switch
const summarys = Array.from(document.querySelectorAll('details'));
// make var with information what element was clicked
let detailsIndex;
summarys.forEach((summary, index) => {
summary.addEventListener('mousedown', ()=>{
if(detailsIndex === index) {
//console.log('clicked in same element');
detailsIndex = index;
}if(detailsIndex != index) {
//console.log("clicked in other element")
detailsIndex = index;
summarys.forEach((summ) => summ.open = false);
}if(detailsIndex == null) {
// console.log('first time clicked')
detailsIndex = index;
}
})
})
h2 {
font-size: 15px;
}
p {
font-size: 12px
}
.container {
display: flex;
width: 100%;
}
details {
display: flex;
}
summary {
display: flex;
align-items: center;
margin-left: 10px;
}
summary::after {
display: flex;
content: '+';
margin-left: 20px;
height: 20px;
width: 20px;
}
<!DOCtype html>
<html>
<head>
</head>
<body>
<div id='container'>
<details>
<summary>
<h2>This is a first</h2>
</summary>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolore tempore quisquam alias veritatis veniam debitis ad asperiores, nobis aliquam minima accusantium corrupti ipsam quasi quo,quam quidem.</p>
</details>
<details>
<summary>
<h2>This is a second</h2>
</summary>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolore tempore quisquam alias veritatis veniam debitis ad asperiores, nobis aliquam minima accusantium corrupti ipsam quasi quo,quam quidem.</p>
</details>
<details>
<summary>
<h2>This is a third</h2>
</summary>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolore tempore quisquam alias veritatis veniam debitis ad asperiores, nobis aliquam minima accusantium corrupti ipsam quasi quo,quam quidem.</p>
</details>
</div>
</body>
</html>