css - 再次单击时如何关闭 Accordion 菜单

标签 css

我仅基于 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/

相关文章:

javascript - 如何在任意位置显示 Nirvana Tikku,径向菜单

css - 将每个导航元素包装在一个 div 中是否合适?

css - React.js + Webpack 无法识别@media 表达式

javascript - 如何添加隐藏的自定义属性

html - 文本超出html中的圆圈边界

html - Safari/IE 图像映射自定义光标无法正常工作

html - 如何使用 Font Awesome 图标为标题提供边框底部

css - 使用 CSS 自定义 Google 图表

javascript - 值不在下拉列表中

html - Rails simple_format 和显示 'Read More' 链接与文本内联