Manifest V3扩展:右键点击仅注入一次Content Script求助
解决方案
方法一:通过DOM标记检测注入状态
这种方法直接在页面DOM中添加标识,background通过执行检测脚本读取该标记判断是否已注入,不受页面刷新外的其他因素影响,可靠性更高。
步骤1:修改payload.js,注入后添加DOM标记
在Content Script执行时,给document添加自定义属性作为已注入的标记,同时修正原代码的消息发送逻辑:
function extract() { // 原提取逻辑保留,修正变量声明避免全局污染 const htmlInnerText = document.documentElement.innerText; const url_exp = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi; const list_url = htmlInnerText.match(url_exp); const ip_exp = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/; const list_ip = htmlInnerText.match(ip_exp); const hash_exp = /\b[A-Fa-f0-9]{32}\b|\b[A-Fa-f0-9]{40}\b|\b[A-Fa-f0-9]{64}\b/g; const list_hash = htmlInnerText.match(hash_exp); chrome.storage.local.set({ list_url, list_ip, list_hash }); // 提取完成后发送消息通知background chrome.runtime.sendMessage({ type: 'extractionComplete' }); } // 添加DOM标记,标记当前页面已注入脚本 document.documentElement.setAttribute('data-payload-injected', 'true'); // 执行提取逻辑 extract(); // 监听background的重新提取指令 chrome.runtime.onMessage.addListener((message) => { if (message.type === 'reExtract') { extract(); } });
步骤2:修改background.js,先检测再注入
在右键点击事件中,先执行检测脚本判断是否已注入,未注入时才加载payload.js,同时修正消息监听的重复绑定问题:
// 全局绑定消息监听,避免每次点击重复添加 chrome.runtime.onMessage.addListener(async (message) => { if (message.type !== 'extractionComplete') return; // 用Promise封装storage操作,避免回调嵌套 const [urlData, ipData, hashData] = await Promise.all([ chrome.storage.local.get('list_url'), chrome.storage.local.get('list_ip'), chrome.storage.local.get('list_hash') ]); const urls = urlData.list_url || []; const ips = ipData.list_ip || []; const hashes = hashData.list_hash || []; if (hashes.length > 0 || urls.length > 0 || ips.length > 0) { chrome.windows.create({ url: "output.html", type: "popup", height: 1000, width: 1000 }); } }); const genericOnClick = async () => { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); if (!tab) return; // 执行检测脚本,读取DOM标记判断是否已注入 const [{result: isInjected}] = await chrome.scripting.executeScript({ target: { tabId: tab.id }, func: () => document.documentElement.hasAttribute('data-payload-injected') }); if (!isInjected) { // 未注入时加载payload.js await chrome.scripting.executeScript({ target: { tabId: tab.id }, files: ["payload.js"] }); } else { // 已注入时,发送指令让脚本重新执行提取逻辑 chrome.tabs.sendMessage(tab.id, { type: 'reExtract' }); } };
方法二:在Background中维护注入状态集合
通过在background中记录已注入的tabId,配合tab关闭/刷新事件清理记录,适合不需要频繁刷新的场景:
步骤1:background.js中维护注入状态
const injectedTabs = new Set(); // 监听tab关闭,移除对应记录 chrome.tabs.onRemoved.addListener((tabId) => injectedTabs.delete(tabId)); // 监听tab刷新,刷新后清空记录(页面刷新后脚本会被清除) chrome.tabs.onUpdated.addListener((tabId, changeInfo) => { if (changeInfo.status === 'loading') injectedTabs.delete(tabId); }); const genericOnClick = async () => { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); if (!tab) return; if (!injectedTabs.has(tab.id)) { await chrome.scripting.executeScript({ target: { tabId: tab.id }, files: ["payload.js"] }); injectedTabs.add(tab.id); } else { chrome.tabs.sendMessage(tab.id, { type: 'reExtract' }); } }; // 消息监听同方法一 chrome.runtime.onMessage.addListener(async (message) => { // ... 同方法一逻辑 });
步骤2:payload.js添加重新提取监听
同方法一中的payload.js消息监听部分即可。
关键修正说明
- 原代码中
chrome.runtime.sendMessage(extract())会立即执行extract并发送其返回值(undefined),改为在extract内部发送消息,确保逻辑顺序正确。 - 原代码每次右键点击都会新增消息监听,导致多次触发弹窗,改为全局绑定一次监听。
内容的提问来源于stack exchange,提问作者tonia j sebastian
相关产品推荐
相关产品推荐

