JavaScript能否嵌套多个事件?代码异常行为排查求助
问题与修复方案
需求与异常现象
- 需求:鼠标悬停id为
poligono的div时,id为divCard的元素随鼠标移动显示;点击poligono可固定divCard位置,再次点击则隐藏。 - 异常:仅点击一次,控制台却同时打印两条日志:
The first click has been made = false和The second click has been made = true,状态被连续切换。
错误原因
- 重复绑定点击事件:每次触发
mouseover时,都会在poligono上绑定新的manejadorEventoClick回调函数实例。多次hover后,点击会触发多个回调,连续切换clickFuera状态,导致两条日志同时出现。 - 事件移除失效:
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
相关产品推荐
相关产品推荐

