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

JavaScript无法移除事件监听器:石头剪刀布游戏交互异常

问题:点击石头剪刀布选项后无法保持悬浮状态(mouseout事件无法移除)

我正在开发一个基础石头剪刀布游戏,设计交互逻辑为:鼠标悬停在选项上时元素上移,点击后元素保持悬浮状态,但实际无法移除mouseout事件监听器,点击后元素仍会回落。

预期效果:点击div后元素变黄并保持悬浮;
实际结果:事件监听器未被移除,元素会再次回落。

问题原因

你当前用的是**内联事件属性(比如onmouseout="out('rock')")**来绑定事件,这种方式本质是在元素上创建了一个匿名函数(内部调用你的out函数并传参),而removeEventListener只能移除通过addEventListener绑定的、函数引用完全匹配的事件,所以你的revokeListeners函数根本删不掉内联绑定的事件。

解决方案

改用JavaScript动态绑定事件,同时用CSS类来管理样式(避免直接操作元素style,更易维护),具体修改如下:

修改后的HTML

<main>
    <h2>Choose A Play:</h2>

    <div id="rock">Rock</div>
    <div id="paper">Paper</div>
    <div id="scissors">Scissors</div>
</main>

修改后的CSS

#rock, #paper, #scissors {
  background-color: #252422;
  font-size: 25px;
  text-align: center;
  color: #fffcf2;
  height: 100px;
  width: 200px;
  padding: 25px;
  margin-top: 50px;
  transition: margin-top 0.2s; /* 添加上移动画,体验更流畅 */
}

#rock, #paper {
  margin-left: 50px;
  float: left;
}

#scissors {
  margin-right: 50px;
  float: right;
}

/* 悬浮状态类 */
.hover {
  margin-top: 10px;
}

/* 选中状态类 */
.selected {
  background-color: #ffba08;
  margin-top: 10px;
}

修改后的JavaScript

const options = ['rock', 'paper', 'scissors'];

// 给每个选项绑定事件
options.forEach(id => {
  const el = document.getElementById(id);
  el.addEventListener('mouseover', () => handleHover(id));
  el.addEventListener('mouseout', () => handleOut(id));
  el.addEventListener('click', () => handleSelect(id));
});

function handleHover(elementId) {
  // 只有未选中的元素才响应悬浮
  if (!document.getElementById(elementId).classList.contains('selected')) {
    document.getElementById(elementId).classList.add('hover');
  }
}

function handleOut(elementId) {
  // 只有未选中的元素才移除悬浮样式
  if (!document.getElementById(elementId).classList.contains('selected')) {
    document.getElementById(elementId).classList.remove('hover');
  }
}

function handleSelect(elementId) {
  const selectedEl = document.getElementById(elementId);
  // 设置选中样式
  selectedEl.classList.add('selected');
  
  // 移除当前元素的所有交互事件,防止后续触发
  selectedEl.removeEventListener('mouseover', () => handleHover(elementId));
  selectedEl.removeEventListener('mouseout', () => handleOut(elementId));
  selectedEl.removeEventListener('click', () => handleSelect(elementId));
  
  // 重置其他未选中元素的状态并禁用交互
  options.forEach(id => {
    if (id !== elementId) {
      const el = document.getElementById(id);
      el.classList.remove('hover');
      el.removeEventListener('mouseover', () => handleHover(id));
      el.removeEventListener('mouseout', () => handleOut(id));
      el.removeEventListener('click', () => handleSelect(id));
    }
  });
}

关键修改点说明

  1. 移除内联事件:所有事件通过addEventListener绑定,这样才能用removeEventListener正确移除
  2. 用CSS类管理样式:把悬浮和选中的样式抽成类,避免直接操作元素的style属性,代码更简洁可维护
  3. 事件逻辑优化:选中元素后,不仅移除自身的mouseout事件,还禁用了其他元素的交互,符合游戏选择后的逻辑
  4. 添加过渡动画:给margin-top加了过渡效果,悬浮和选中的切换更平滑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 09:35:00