You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何将click事件从dropdown改为select后,菜单关闭功能恢复正常?

问题:点击下拉选项后菜单无法关闭的原因分析

我有一个带有menu类的div,内部包含选项列表,默认设置display:none。当用户点击时,程序会添加menu-open类,使菜单可见。我的需求是用户选择选项后立即关闭菜单,计划通过点击事件移除menu-open类,让元素恢复display:none,但最初实现时该功能失效。我将JS代码第12行的dropdown.addEventListener("click", () => {...})改为select.addEventListener("click", () => {...})后问题解决,但无法解释该行为,希望有人能说明原因。

相关代码

JavaScript

const dropdowns = document.querySelectorAll(".dropdown");

// Loop through all dropdown elements

dropdowns.forEach((dropdown) => {
  const select = dropdown.querySelector(".select");
  const caret = dropdown.querySelector(".caret");
  const menu = dropdown.querySelector(".menu");
  const options = dropdown.querySelectorAll(".menu li");
  const selected = dropdown.querySelector(".selected");

  dropdown.addEventListener("click", () => {
    menu.classList.toggle("menu-open");

    options.forEach((option) => {
      option.addEventListener("click", () => {
        menu.classList.remove("menu-open");

        options.forEach((option) => {
          option.classList.remove("active");
        });
      });
    });
  });
});

CSS

/*Global settings*/

html {
  font-size: 62.5%;
}

*,
::after,
::before {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}


/*-------------------------------------------------------------*/

body {
  font-family: "Roboto";
  background-color: #23242a;
  color: #fff;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

.dropdown {
  margin: 4rem;
  position: relative;
}

.select {
  min-width: 15rem;
  border-radius: 0.7rem;
  background-color: #2a2f3b;
  padding: 1rem;
  display: flex;
  justify-content: space-between;
  cursor: pointer;
}

.select:hover {
  background-color: #323741;
}

.caret {
  transition: 0.3s;
}

.menu {
  background-color: #323741;
  padding: 0.5rem 0.5rem;
  border-radius: 0.7rem;
  position: absolute;
  top: 4rem;
  width: 100%;
  cursor: pointer;
  display: none;
}

.menu li {
  border-radius: 0.2rem;
  list-style-type: none;
  padding: 0.3rem 0.8rem;
  margin: 0.3rem;
}

.menu li:hover {
  background-color: #2a2d35;
}

.active {
  background-color: #23242a;
}


/*Clicked Styles (Added later in JS) */

.caret-rotate {
  transform: rotate(180deg);
}

.menu-open {
  display: block;
  opacity: 1;
}

HTML

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100;400;700&display=swap" rel="stylesheet" />
  <link rel="stylesheet" href="style.css" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css" />

  <title>Drop-down</title>
</head>

<body>
  <div class="dropdown">
    <div class="select">
      <span class="selected">Figma</span>
      <div class="caret"><i class="fa-solid fa-caret-down"></i></div>
    </div>
    <ul class="menu">
      <li>Framer</li>
      <li>Sketch</li>
      <li>Invision Studio</li>
      <li class="active">Figma</li>
      <li>Adobe XD</li>
    </ul>
  </div>

  <div class="dropdown">
    <div class="select">
      <span class="selected">Facebook</span>
      <div class="caret"><i class="fa-solid fa-caret-down"></i></div>
    </div>
    <ul class="menu">
      <li class="active">FaceBook</li>
      <li>instagram</li>
      <li>Twitter</li>
      <li>Linkedin</li>
      <li>Tik Tok</li>
    </ul>
  </div>
</body>
<script src="app.js"></script>

</html>

原因解释

核心问题是事件冒泡和toggle方法的执行逻辑冲突:

  • 原代码(绑定dropdown点击事件)的问题:
    当你点击菜单里的<li>选项时,事件会沿着DOM树向上冒泡,先执行<li>自身的点击事件(移除menu-open类,菜单隐藏),然后事件冒泡到父元素.dropdown,触发绑定在它身上的点击事件,里面的menu.classList.toggle("menu-open")会再次执行——这时候因为刚移除了类,toggle会重新添加menu-open,导致菜单立刻又显示出来,看起来就是关闭功能失效。
    另外还有一个隐藏问题:每次点击.dropdown都会给所有<li>重新绑定点击事件,多次点击后同一个选项会绑定多个事件,触发时会重复执行移除操作,属于代码冗余。

  • 修改后(绑定select点击事件)的解决原理:
    看HTML结构,.menu是.dropdown的直接子元素,但和.select是同级关系,不属于.select的子元素。所以点击<li>时,事件只会冒泡到.menu和.dropdown,不会触发.select的点击事件。这时候<li>的点击事件移除menu-open后,没有后续的toggle操作把类加回来,菜单就会保持隐藏状态,符合预期。

内容的提问来源于stack exchange,提问作者Salvarez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 06:13:11