如何在Chrome扩展DOM/URL变更时重新执行content.js脚本?
解决Chrome扩展在Facebook商务平台标签切换后按钮消失的问题
你的问题本质是Facebook商务平台是单页应用(SPA)——切换标签时不会刷新整个页面,只是动态更新DOM内容,而你的content.js默认只在页面首次加载时执行一次,所以切换回Campaigns标签后,新渲染的DOM元素没有被处理,按钮自然就消失了。下面给你一套完整的解决方案:
核心思路
我们需要做三件事:
- 把按钮生成的核心逻辑封装成可重复调用的函数
- 用
MutationObserver监听DOM动态变化,自动触发逻辑 - 让background脚本在标签切换/URL变化时通知content.js重新执行逻辑
代码修改步骤
1. 重构content.js:封装逻辑+监听DOM+响应消息
把按钮生成的代码抽成独立函数,同时添加DOM监听和消息监听:
// 封装核心按钮设置逻辑,方便重复调用 function setupButtons() { // 修改"Reporting Ends"文本 const botme = $("_643l:contains('Reporting Ends')"); botme.text("Add?"); // 替换年份元素为按钮 const year = new Date().getFullYear(); const boxspot = $("_1b33:contains(" + year + ")"); boxspot.replaceWith('<button class="open-dialog-btn">Bot me!</button><div id="dialog"></div>'); // 用事件委托绑定点击(避免动态元素绑定失效) $(document).off('click', '.open-dialog-btn').on('click', '.open-dialog-btn', function() { const popup = window.open("", "popupWindow", "width=600, height=400, scrollbars=yes"); $(popup.document.body).html("<textarea>It works!</textarea>"); }); } // 页面首次加载时执行 $(document).ready(function() { setupButtons(); // 监听DOM变化:当Campaigns区域更新时重新生成按钮 // 建议替换成更精确的父容器(比如Campaigns列表的容器),减少性能消耗 const targetContainer = document.body; const observerConfig = { childList: true, subtree: true }; const domObserver = new MutationObserver((mutations) => { // 检查目标元素是否存在,避免无意义触发 if ($("_643l:contains('Reporting Ends')").length && $("_1b33:contains(" + new Date().getFullYear() + ")").length) { setupButtons(); } }); domObserver.observe(targetContainer, observerConfig); }); // 监听background脚本发来的刷新指令 chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === 'refreshButtons') { setupButtons(); sendResponse({ status: "buttons refreshed" }); } });
2. 优化background.js:监听标签切换和URL变化
确保在两种场景下通知content.js:用户导航到Campaigns页面,或者从其他标签切换回Campaigns页面:
// 精准匹配Campaigns页面的URL const campaignsUrlRegex = /^https?:\/\/(www\.)?business\.facebook\.(com|\w\w(\.\w\w)?)\/adsmanager\/manage\/campaigns.*$/; // 监听标签URL更新(比如从其他页面导航到Campaigns) chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { if (changeInfo.url && campaignsUrlRegex.test(changeInfo.url)) { chrome.tabs.sendMessage(tabId, { action: 'refreshButtons' }); } }); // 监听标签激活(切换到已经打开的Campaigns标签) chrome.tabs.onActivated.addListener((activeInfo) => { chrome.tabs.get(activeInfo.tabId, (tab) => { if (campaignsUrlRegex.test(tab.url)) { chrome.tabs.sendMessage(activeInfo.tabId, { action: 'refreshButtons' }); } }); }); // 保留原有的browser action点击逻辑 chrome.browserAction.onClicked.addListener((tab) => { chrome.tabs.sendMessage(tab.id, { action: "pageToSpeech" }, () => {}); });
3. 关键注意事项
- 选择器稳定性:Facebook经常会修改页面的class名(比如
_643l、_1b33),如果后续按钮消失,先检查这些选择器是否还能匹配到目标元素。 - 监听范围优化:尽量找到Campaigns列表的具体父容器(比如通过浏览器开发者工具定位),替换掉
document.body作为监听目标,减少不必要的DOM监听触发,提升性能。 - 事件委托:用
$(document).on('click', '.open-dialog-btn', ...)代替直接绑定按钮点击,因为动态生成的元素无法直接绑定事件,事件委托可以解决这个问题。
内容的提问来源于stack exchange,提问作者lob0
相关产品推荐
相关产品推荐

