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

Chrome扩展中Checkbox值为false时,开启状态对应函数仍执行如何解决

问题根源
  • 最核心的问题是开关开启时给所有文本元素绑定了mouseover、mouseout、click三个事件监听器,但关闭开关时仅清除了元素的背景色,没有移除绑定的事件监听器,这些监听器会一直留在DOM元素上,所以关闭开关后hover、点击文本还是会触发之前的逻辑。
  • 另外你当前的代码每次打开开关都会重新给元素绑定一次监听器,反复开关会导致同一个元素绑定多份相同的监听器,额外占用性能。
修复方案

需要修改content.js的逻辑,核心是要把匿名事件监听器抽成具名函数,同时全局存储开关状态和绑定的监听器,方便关闭时统一移除。

第一步:新增全局存储变量

先在content.js最顶部添加以下代码:

// 全局存储开关状态
let isSwitchOn = false;
// 存储每个元素绑定的监听器,移除时需要和绑定时的函数引用完全一致
const eventListenersMap = new WeakMap();
// 把不变的常量提出来,避免重复声明
const colors = ['#ffadad', '#ffd6a5', '#fdffb6', '#caffbf', '#bdb2ff', '#9fdfff'];
const findFontModal = 'findfont.html'

第二步:抽离事件处理函数

把之前写在循环里的匿名事件处理函数抽成全局具名函数:

// hover高亮处理
function handleMouseOver(e) {
  e.target.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
  e.target.style.cursor = "pointer";
}
// hover取消高亮处理
function handleMouseOut(e) {
  e.target.style.backgroundColor = null;
}
// 点击弹出modal处理
async function handleClick(e) {
  e.stopPropagation();
  const showModal = async () => {
    const modal = document.createElement('dialog');
    modal.setAttribute("style",`
    border: none;
    border-radius:20px;
    background-color:#fafafa;
    position: absolute;
    z-index:10000000000000;
    box-shadow: rgba(0, 0, 0, 0.2) 0px 18px 50px -10px;
    `);
    modal.innerHTML = `<iframe id="popup-content" scrolling="no" style="height:155px; width:347px; z-index:10000000000000;" frameBorder="0"></iframe>`;
    modal.style.top = e.pageY+"px";
    modal.style.left = e.pageX+"px";
    document.body.appendChild(modal);
    const dialog = document.querySelector("dialog");
    dialog.show();
    // 修复modal关闭事件重复绑定的问题
    function closeModal() {
      document.body.removeChild(modal);
      dialog.close();
      document.body.removeEventListener('click', closeModal);
    }
    document.body.addEventListener('click', closeModal);
    const iframe = document.getElementById("popup-content");
    iframe.src = chrome.runtime.getURL("findfont.html")
  }
  fetch(chrome.runtime.getURL(findFontModal))
    .then(r => r.text())
    .then(html => {
      showModal();
  });
}

第三步:修改开关开启逻辑

修改request.switchStatus === "on"对应的代码块,增加重复开启判断,绑定事件后存储到Map中:

if (request.switchStatus === "on") {
  // 开关已经开启的情况下直接返回,避免重复绑定
  if (isSwitchOn) {
    sendResponse({status: "done"});
    return;
  }
  isSwitchOn = true;
  const allText = document.querySelectorAll('h1, h2, h3, h4, h5, p, li, td, caption, span, a');
  for (let i = 0; i < allText.length; i++) {
    const el = allText[i];
    // 绑定监听器
    el.addEventListener('mouseover', handleMouseOver);
    el.addEventListener('mouseout', handleMouseOut);
    el.addEventListener('click', handleClick);
    // 存入Map方便后续移除
    eventListenersMap.set(el, {
      mouseover: handleMouseOver,
      mouseout: handleMouseOut,
      click: handleClick
    });
  }
  sendResponse({status: "done"});
  return;
}

第四步:修改开关关闭逻辑

修改request.switchStatus === "off"对应的代码块,增加移除事件监听器的逻辑:

else if (request.switchStatus === "off") {
  // 开关已经关闭的情况下直接返回
  if (!isSwitchOn) {
    sendResponse({status: "done"});
    return;
  }
  isSwitchOn = false;
  const allText = document.querySelectorAll('h1, h2, h3, h4, h5, p, li, td, caption, span, a');
  for (let i = 0; i < allText.length; i++) {
    const el = allText[i];
    el.style.backgroundColor = null;
    // 移除之前绑定的监听器
    const listeners = eventListenersMap.get(el);
    if (listeners) {
      el.removeEventListener('mouseover', listeners.mouseover);
      el.removeEventListener('mouseout', listeners.mouseout);
      el.removeEventListener('click', listeners.click);
      eventListenersMap.delete(el);
    }
  }
  sendResponse({status: "done"});
}

额外优化

你popup.js里声明的checkedAttr变量完全没有使用,可以直接删除,没有实际作用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 03:45:03