我仅基于 HTML 和 CSS 构建了一个简单的 Accordion 菜单。功能很好,但问题是当您单击打开的 Accordion 时它不会关闭。
我可以用 CSS 来实现还是需要 JavaScript?
.middle a {
text-decoration: none;
}
.menu {
width: 100%;
overflow: hidden;
}
.item {
border-top: 1px solid #2980b9;
overflow: hidden;
}
.btn {
display: block;
padding: 16px 20px;
background: #3498db;
color: white;
position: relative;
}
.btn:before {
content: "";
position: absolute;
width: 14px;
height: 14px;
background: #3498db;
left: 20px;
bottom: -7px;
transform: rotate(45deg)
}
a i {
margin-right: 10px;
margin-left: 10px
}
.smenu {
background: white;
overflow: hidden;
transition: max-height 0.3s;
max-height: 0;
}
.smenu a {
display: block;
padding: 16px 26px;
font-size: 14px;
margin: 4px 0;
position: relative;
}
.smenu a:before {
content: "";
position: absolute;
width: 6px;
height: 100%;
background: #3498db;
left: 0;
top: 0;
transition: 0.3s;
opacity: 0;
}
a:hover:before {
opacity: 1;
}
.item:target .smenu {
max-height: 100%;
}
.item {
list-style-type: none
}
<div class="middle">
<div class="menu">
<li class="item" id="aboutus">
<a href="#aboutus" class="btn">About Us</a>
<div class="smenu">
<a href="#">1</a>
<a href="#">2</a>
<a href="#">3</a>
<a href="#">4</a>
<a href="#">5</a>
<a href="#">6</a>
</div>
</li>
<li class="item" id="contactus">
<a href="#contactus" class="btn">Contact Us</a>
<div class="smenu">
<a><i class="fas fa-phone"></i>000-000-000</a>
<a><i class="fas fa-envelope-open"></i>Send Us An Email</a>
<a>ABCDEFG</a>
<a>P.O> Box 00000</a>
<a>New York, New York 000000</a>
<a><i class="fas fa-clock"></i>Monday - Friday: 9AM - 5PM ET</a>
<a><i class="fas fa-window-close"></i>Saturday-Sunday: Closed</a>
<a><i class="fas fa-desktop"></i>Online: 24/7</a>
</div>
</li>
<li class="item" id="sitelinks">
<a href="#sitelinks" class="btn">Site Links</a>
<div class="smenu">
<a href="#">1</a>
<a href="#">2</a>
<a href="#">3</a>
<a href="#">4t</a>
<a href="#">5</a>
<a href="#">6</a>
</div>
</li>
</div>
</div>
最佳答案
问题
打开 Accordion 面板之一是基于该面板 li class="item"
是当前的目标(散列)
.item:target .smenu {
max-height: 100%;
}
然后,关闭该面板的唯一方法是 <li>
不再是目标,再次单击该元素将不会这样做;您将不得不单击其他内容,或者求助于 javascript — 因此,“我可以使用 CSS 做到这一点还是需要 JavaScript?” 的基本答案是您需要 javascript。 p>
Javascript 做到了
好消息是它是一段非常简单的 javascript。在这里,包裹在 DOMContentLoaded
中如果它位于从页面链接的自己的 .js 文件中,您需要这样做:
document.addEventListener("DOMContentLoaded", function(event) {
const items = document.querySelectorAll('.menu li.item');
for (let item of items) {
item.addEventListener('click', function(e) {
if ('#'+e.currentTarget.id === location.hash) {
e.preventDefault();
window.location.hash = '';
}
});
}
});
它有什么作用?
此查询 (querySelectorAll) 所有菜单项; li.item
.menu
内的 s
然后它遍历每一个并为“点击”事件附加一个事件监听器。就是这样。
事件监听器本身也很简单。它使用事件 e
并获得 id
点击的当前目标,如果它与当前 location.hash 相同,这意味着您正在点击已经打开的内容,所以...阻止默认操作(再次导航到哈希),并清除散列。
现在清除散列后,.item:target
CSS 选择器不匹配任何内容,因此之前打开的 Accordion Pane 关闭。
作为堆栈片段
当我们创建一个代码片段时,代码片段负责等待 DOM 准备就绪,因此我们将移除该包装器。就是这样,我所做的只是将一些 Javascript 添加到您自己的代码段中:
const items = document.querySelectorAll('.menu li.item');
for (let item of items) {
item.addEventListener('click', function(e) {
if ('#'+e.currentTarget.id === location.hash) {
e.preventDefault();
window.location.hash = '';
}
});
}
.middle a {
text-decoration: none;
}
.menu {
width: 100%;
overflow: hidden;
}
.item {
border-top: 1px solid #2980b9;
overflow: hidden;
}
.btn {
display: block;
padding: 16px 20px;
background: #3498db;
color: white;
position: relative;
}
.btn:before {
content: "";
position: absolute;
width: 14px;
height: 14px;
background: #3498db;
left: 20px;
bottom: -7px;
transform: rotate(45deg)
}
a i {
margin-right: 10px;
margin-left: 10px
}
.smenu {
background: white;
overflow: hidden;
transition: max-height 0.3s;
max-height: 0;
}
.smenu a {
display: block;
padding: 16px 26px;
font-size: 14px;
margin: 4px 0;
position: relative;
}
.smenu a:before {
content: "";
position: absolute;
width: 6px;
height: 100%;
background: #3498db;
left: 0;
top: 0;
transition: 0.3s;
opacity: 0;
}
a:hover:before {
opacity: 1;
}
.item:target .smenu {
max-height: 100%;
}
.item {
list-style-type: none
}
<div class="middle">
<div class="menu">
<li class="item" id="aboutus">
<a href="#aboutus" class="btn">About Us</a>
<div class="smenu">
<a href="#">1</a>
<a href="#">2</a>
<a href="#">3</a>
<a href="#">4</a>
<a href="#">5</a>
<a href="#">6</a>
</div>
</li>
<li class="item" id="contactus">
<a href="#contactus" class="btn">Contact Us</a>
<div class="smenu">
<a><i class="fas fa-phone"></i>000-000-000</a>
<a><i class="fas fa-envelope-open"></i>Send Us An Email</a>
<a>ABCDEFG</a>
<a>P.O> Box 00000</a>
<a>New York, New York 000000</a>
<a><i class="fas fa-clock"></i>Monday - Friday: 9AM - 5PM ET</a>
<a><i class="fas fa-window-close"></i>Saturday-Sunday: Closed</a>
<a><i class="fas fa-desktop"></i>Online: 24/7</a>
</div>
</li>
<li class="item" id="sitelinks">
<a href="#sitelinks" class="btn">Site Links</a>
<div class="smenu">
<a href="#">1</a>
<a href="#">2</a>
<a href="#">3</a>
<a href="#">4t</a>
<a href="#">5</a>
<a href="#">6</a>
</div>
</li>
</div>
</div>
最后,因为您不需要 items
对于除了循环之外的任何事情,您甚至不必将它们分配给变量。
这是一个进一步简化的版本,它用箭头函数替换了显式函数。
document.addEventListener("DOMContentLoaded", function(event) {
document.querySelectorAll('.menu li.item')
.forEach(element =>
element.addEventListener('click',
e => {
if ('#'+e.currentTarget.id === location.hash) {
e.preventDefault();
window.location.hash = '';
}
})
)
});
if ('#'+e.currentTarget.id === ...
也可以变成谓词,但我会把它留给读者作为练习。
关于css - 再次单击时如何关闭 Accordion 菜单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55691706/