Chrome扩展中setInterval监听按钮导致点击事件多次触发如何解决
问题原因
你的代码核心问题是setInterval每秒执行一次回调,只要检测到按钮存在就新增一个点击监听器,运行时间越久按钮上绑定的同功能监听器越多,点击一次就会触发多次runAction调用。此外原代码的属性选择器[slot=primary-content-area漏写了闭合的],会导致选择器匹配失败。
解决方案
最简方案(推荐,无定时器性能最优)
利用jQuery的事件委托机制,直接给按钮的父容器绑定点击事件,自动匹配动态出现的sn-inbox按钮,完全不需要轮询DOM,也不会出现重复绑定问题:
$(function(){ const url = window.location.href; // 父容器委托点击事件,自动匹配所有符合选择器的子元素 $("[slot=primary-content-area]").eq(4).on('click', 'sn-inbox', function() { console.log("clicked"); runAction(url); }) })
快速修复方案(不改动原有轮询逻辑)
给绑定过监听器的按钮加自定义标记,避免重复绑定即可,修改后代码如下:
$(function(){ var url=window.location.href; findAction(url); }) function findAction(url){ // 事件处理函数提到定时器外,避免重复创建 function myFunction() { console.log("clicked"); runAction(url) } setInterval(()=>{ const Acceptbtn = $("[slot=primary-content-area]")[4]?.querySelector("sn-inbox"); // 判断按钮存在且未绑定过监听器 if(Acceptbtn && !Acceptbtn.dataset.hasBindClick){ Acceptbtn.addEventListener('click', myFunction); // 添加绑定标记,下次轮询跳过 Acceptbtn.dataset.hasBindClick = '1'; } },1000); }
优化轮询方案(性能高于setInterval)
如果你需要持续监听DOM变化但不想占用定时器资源,可以改用MutationObserver监听指定区域的DOM更新,只有DOM发生变化时才检测按钮是否存在:
$(function(){ const url = window.location.href; function myFunction() { console.log("clicked"); runAction(url) } // 要监听的父容器节点 const observerTarget = $("[slot=primary-content-area]")[4]; const observer = new MutationObserver(() => { const Acceptbtn = observerTarget.querySelector("sn-inbox"); if(Acceptbtn && !Acceptbtn.dataset.hasBindClick){ Acceptbtn.addEventListener('click', myFunction); Acceptbtn.dataset.hasBindClick = '1'; } }); // 配置监听子节点、子树变化 observer.observe(observerTarget, { childList: true, subtree: true }); })
参考示意图
按钮所在DOM结构:
点击按钮后效果:
内容的提问来源于stack exchange,提问作者Sharon
相关产品推荐
相关产品推荐

