Chrome扩展中点击事件仅第二次触发的问题排查
问题原因及修复方案
核心问题分析
- 动态元素事件绑定失效:注入的HTML元素是动态添加到DOM中的,直接绑定元素事件时,元素尚未存在,导致首次点击无响应。
- 变量重复声明报错:全局作用域内重复使用
let声明visitedCount、visitSpeed等变量,引发运行时错误,中断事件逻辑执行。 - IndexedDB初始化异步问题:
createDB()是异步操作,首次点击时db可能未初始化完成,调用addUser时会抛出错误,导致事件流程中断。 - 定时器未清理:点击Stop后,已设置的
setTimeout仍会继续执行,影响状态判断。
具体修复步骤
1. 改用事件委托绑定点击事件
针对动态注入的元素,将事件绑定到document或稳定的父元素上:
// 替换原事件绑定代码 $(document).on("click", "#counter--status", function (e) { if ($(this).text() === "Start") { $(this).text("Stop"); $(data).each(function (index, username) { let eUsername = username; setTimeout(function () { if ($("#counter--status").text() == "Stop") { $("#container--profiles--visited").html(visitedCount); var percentRound = ( (visitedCount / data.length) * 100 * 1.025 ).toFixed(0); $("#container--bottom--status").html( "Remaining: " + percentRound + "% - Visiting: " + eUsername ); if (jQuery.inArray(eUsername, visited) == -1) { visited.push(eUsername); visitedCount += 1; fetch("https://www.theurls.com", { headers: { "x-api-key": "XXX", "x-session-id": "XXX", }, }) .then((response) => response.json()) .then((data) => addUser(eUsername)); } } }, visitSpeed * index); }); } else { $("#counter--status").text("Start"); $("#counter--count").html(""); } });
2. 清理重复的变量声明
删除全局作用域内重复的let声明,保留一份变量定义:
// 保留顶部的变量声明,删除后续重复部分 data = ["test", "test2", "test3"]; let ids = []; let visitedCount = 0; let visitSpeed = 1000; let visited = []; let db = null; const mVisitDB = new Map(); // 注入HTML injectedhtml = ` <div id="container--start-counter"> <span id="counter--status"> Start </span> <span id="counter--count"></span> </div>`; // 仅赋值,不再重复声明 data = [];
3. 确保IndexedDB初始化完成后再处理事件
修改createDB(),添加初始化完成回调,避免db未就绪时调用相关方法:
function createDB() { const request = indexedDB.open("VisitDB", 1); request.onupgradeneeded = function(event) { db = event.target.result; // 创建所需的对象仓库 if (!db.objectStoreNames.contains("username")) { db.createObjectStore("username", { keyPath: "user" }); } if (!db.objectStoreNames.contains("blocked_user")) { db.createObjectStore("blocked_user", { keyPath: "user" }); } }; request.onsuccess = function(event) { db = event.target.result; // DB初始化完成后再绑定事件 bindCounterEvent(); }; request.onerror = function(event) { console.error("IndexedDB初始化失败:", event.target.error); }; } // 封装事件绑定逻辑 function bindCounterEvent() { $(document).on("click", "#counter--status", function (e) { // 原事件逻辑 }); }
4. 添加定时器清理逻辑
点击Stop时,清除所有未执行的定时器,避免后续逻辑继续运行:
let timeoutIds = []; // 新增存储定时器ID的数组 $(document).on("click", "#counter--status", function (e) { if ($(this).text() === "Start") { $(this).text("Stop"); timeoutIds = []; // 清空之前的定时器ID $(data).each(function (index, username) { let eUsername = username; const timeoutId = setTimeout(function () { if ($("#counter--status").text() == "Stop") { // 原逻辑... } }, visitSpeed * index); timeoutIds.push(timeoutId); // 保存定时器ID }); } else { $("#counter--status").text("Start"); $("#counter--count").html(""); // 清除所有未执行的定时器 timeoutIds.forEach(id => clearTimeout(id)); timeoutIds = []; } });
内容的提问来源于stack exchange,提问作者wakawaka
相关产品推荐
相关产品推荐

