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

如何阻止按钮子元素触发mouseenter事件并正确移除事件?

按钮内部图片触发mouseenter重复执行及事件无法移除的解决方法

问题背景

按钮内部包含图片时,hover操作会同时触发按钮和图片的mouseenter事件,导致音效重复播放;同时现有两种JS写法都无法在按钮禁用后成功移除mouseenter事件。


相关代码

HTML(核心按钮结构)

<div class="catalogue-hidden">
  <div id="product-1" class="product estusFlask">
    <img src="./products/Item_Estus_Flask.png" />
    <span>Estus Flask</span>
    <button id="btn-1" class="button">
      1000
      <img src="./icons/soul_of_a_proud_paladin.png" />
    </button>
  </div>
  <!-- 其他产品按钮结构类似 -->
</div>

现有JS写法问题

写法一(捕获阶段绑定)

function selectSfx() {
  var audio = document.querySelector(".selectSfx");
  audio.currentTime = 0;
  audio.play();
}

for (let idNumber = 1; idNumber < 13; idNumber++) {
  setTimeout(() => {
    document
      .getElementById(`btn-${idNumber}`)
      .addEventListener("mouseenter", selectSfx, true);

    document
      .getElementById(`btn-${idNumber}`)
      .addEventListener("click", (e) => {
        condition++;
        okSfx();
        document.getElementById(`product-${idNumber}`).className = "product-fake";
        document.getElementById(`btn-${idNumber}`).disabled = true;
        // 移除事件失败,需严格匹配捕获阶段参数
        document
          .getElementById(`btn-${idNumber}`)
          .removeEventListener("mouseenter", selectSfx, true);
      });
  }, 4000);
}
  • 优点:通过捕获阶段绑定避免了图片触发重复事件
  • 问题:移除事件时需严格匹配第三个参数true,且可能因元素加载时机问题失效

写法二(匿名函数绑定)

function selectSfx() {
  var audio = document.querySelector(".selectSfx");
  audio.currentTime = 0;
  audio.play();
}

for (let idNumber = 1; idNumber < 14; idNumber++) {
  setTimeout(() => {
    document
      .getElementById(`btn-${idNumber}`)
      .addEventListener("mouseenter", (e) => {
        selectSfx();
      });
  }, 4000);
}
  • 优点:同样避免了图片重复触发
  • 问题:匿名函数无法被removeEventListener识别,无法移除事件

解决方案

1. 从根源解决重复触发问题:CSS禁用图片鼠标事件

给按钮内部的图片添加pointer-events: none,让图片不响应任何鼠标事件,hover图片时只会触发按钮的mouseenter:

.button img {
  pointer-events: none;
}

2. 修复事件无法移除问题:使用命名函数+存储引用

避免使用匿名函数,将每个按钮的事件处理函数引用存储起来,确保移除时能精准匹配:

function selectSfx() {
  const audio = document.querySelector(".selectSfx");
  audio.currentTime = 0;
  audio.play();
}

// 存储每个按钮的事件处理函数引用
const buttonHandlers = {};

for (let idNumber = 1; idNumber < 13; idNumber++) {
  setTimeout(() => {
    const btn = document.getElementById(`btn-${idNumber}`);
    if (!btn) return; // 确保元素已加载

    // 绑定命名函数
    buttonHandlers[idNumber] = selectSfx;
    btn.addEventListener("mouseenter", buttonHandlers[idNumber]);

    btn.addEventListener("click", () => {
      condition++;
      console.log(condition);
      okSfx();

      document.getElementById(`product-${idNumber}`).className = "product-fake";
      btn.disabled = true;

      // 精准移除事件
      btn.removeEventListener("mouseenter", buttonHandlers[idNumber]);

      if (condition >= 11) {
        document.querySelector(".product-hidden").className = "product";
        document.getElementById("btn-12").className = "button";
      }
    });
  }, 4000);
}

3. 更优方案:事件委托

将事件绑定到父元素,无需逐个绑定/移除事件,且自动支持动态生成的元素:

function selectSfx() {
  const audio = document.querySelector(".selectSfx");
  audio.currentTime = 0;
  audio.play();
}

// 委托mouseenter事件到父容器
document.querySelector(".catalogue-hidden").addEventListener("mouseenter", (e) => {
  const btn = e.target.closest(".button");
  // 仅处理未禁用的按钮
  if (btn && !btn.disabled) {
    selectSfx();
  }
});

// 委托click事件到父容器
document.querySelector(".catalogue-hidden").addEventListener("click", (e) => {
  const btn = e.target.closest(".button");
  if (!btn || btn.disabled) return;

  const idNumber = btn.id.split("-")[1];
  condition++;
  console.log(condition);
  okSfx();

  document.getElementById(`product-${idNumber}`).className = "product-fake";
  btn.disabled = true;

  if (condition >= 11) {
    document.querySelector(".product-hidden").className = "product";
    document.getElementById("btn-12").className = "button";
  }
});
  • 优势:无需手动移除事件,通过!btn.disabled判断自动禁用hover音效;代码更简洁,性能更优。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 03:40:22