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

JavaScript能否嵌套多个事件?代码异常行为排查求助

问题与修复方案

需求与异常现象

  • 需求:鼠标悬停id为poligono的div时,id为divCard的元素随鼠标移动显示;点击poligono可固定divCard位置,再次点击则隐藏。
  • 异常:仅点击一次,控制台却同时打印两条日志:The first click has been made = false和The second click has been made = true,状态被连续切换。

错误原因

  1. 重复绑定点击事件:每次触发mouseover时,都会在poligono上绑定新的manejadorEventoClick回调函数实例。多次hover后,点击会触发多个回调,连续切换clickFuera状态,导致两条日志同时出现。
  2. 事件移除失效:removeEventListener需要和绑定的是同一个函数实例才能生效,但每次mouseover生成的都是新的函数,旧的回调无法被移除,一直残留。

修复后的代码

JavaScript

let clickFuera = true;
let isClickEventBound = false; // 标记是否已绑定点击事件
let manejadorEventoMovMouse = null;

const manejadorEventoClick = function() {
  const divCard = document.getElementById('divCard');
  const poligono = document.getElementById('poligono');
  
  if (clickFuera) {
    document.removeEventListener("mousemove", manejadorEventoMovMouse);
    divCard.style.display = "block";
    clickFuera = false;
    console.log("The first click has been made  = " + clickFuera);
  } else {
    divCard.style.display = "none";
    clickFuera = true;
    isClickEventBound = false; // 解绑后重置标记
    console.log("The second click has been made = " + clickFuera);
  }
};

function inOutHover(idDivCard, isHover, idPoligono) {
  const divCard = document.getElementById(idDivCard);
  const poligono = document.getElementById(idPoligono);

  // 只创建一次鼠标移动回调
  if (!manejadorEventoMovMouse) {
    manejadorEventoMovMouse = function(e) {
      divCard.style.left = e.pageX + 40 + "px";
      divCard.style.top = e.pageY + 5 + "px";
    };
  }

  if (isHover) {
    if (!clickFuera) {
      // 如果已经点击固定,hover时不重新绑定鼠标移动和点击事件
      return;
    }
    document.addEventListener("mousemove", manejadorEventoMovMouse);
    divCard.style.display = "block";
    // 只绑定一次点击事件
    if (!isClickEventBound) {
      poligono.addEventListener("click", manejadorEventoClick);
      isClickEventBound = true;
    }
  } else {
    if (clickFuera) {
      // 未点击固定时,mouseout才隐藏卡片并移除事件
      document.removeEventListener("mousemove", manejadorEventoMovMouse);
      divCard.style.display = "none";
      if (isClickEventBound) {
        poligono.removeEventListener("click", manejadorEventoClick);
        isClickEventBound = false;
      }
    }
  }
}

CSS

body {
  font-family: Arial, sans-serif;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #f0f0f0;
  margin: 0;
}

.poligono {
  width: 100px;
  height: 100px;
  background-color: #3498db;
  cursor: pointer;
}

.divCard {
  display: none;
  position: absolute;
  background-color: #fff;
  border: 1px solid #ccc;
  padding: 10px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

HTML

<body>
  <div id="poligono" class="poligono" onmouseover="inOutHover('divCard', true, 'poligono')" onmouseout="inOutHover('divCard', false, 'poligono')"></div>
  <div id="divCard" class="divCard">This is a card</div>

  <script src="script.js"></script>
</body>

关键优化点

  • 将点击和鼠标移动回调函数移到全局,确保每次绑定的是同一个实例,移除时能匹配成功;
  • 添加isClickEventBound标记,防止重复绑定点击事件;
  • 在mouseover和mouseout时判断clickFuera状态,避免点击固定后,hover/out事件干扰卡片状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 14:08:14