你把这个问题过于复杂化了,这会导致很多逻辑错误。
您已将后台页面设置为充当消息代理,并且内容脚本本身会触发更新您的page_html
多变的。然后弹出窗口会通过另一条消息提取该数据。
注意page_html
不会包含current无论如何,选项卡的数据:您将用最后一个数据覆盖此数据loaded tab.
你能做的就是完全省去中间商(即background.js
)。我想您对向弹出窗口发送消息通常是一个坏主意(不能保证它是打开的)这一事实感到困惑,但相反的方式通常是安全的(并且您可以使其始终安全)。
解决方案 1(不好,但出于教育目的)
您的应用程序的逻辑是:一旦用户单击按钮,就制作快照在那一刻。因此,不要让您的内容脚本立即执行其工作,而是添加一个消息侦听器:
// content.js
chrome.runtime.onMessage(function(message, sender, sendResponse) {
else if (request.message == 'getPageDOM')
sendResponse(DOMtoString(document));
});
function DOMtoString(document_root) { ... }
在弹出窗口中请求它:
// popup.js
// (Inside the click listener)
chrome.tabs.query({currentWindow: true, active: true}, function(tabs) {
// Note that sending a message to a content script is different
chrome.tabs.sendMessage(tabs[0].id, {message:'getPageDOM'}, function(response) {
download(response, "download.html", "text/html");
});
});
然而,该解决方案并非 100% 稳健。如果内容脚本没有注入到页面中将会失败(这可能会发生)。但这个问题是可以解决的。
解决方案2
我们不要假设内容脚本已注入。事实上,大多数时候您不需要自动注入它,仅当用户单击您的按钮时才需要。
因此,从清单中删除内容脚本,确保您有主机权限 ("<all_urls>"
效果很好,但考虑一下activeTab允许),以及使用程序化注入.
有一种很少使用的编程注入形式,它收集最后执行的语句的值。我们将使用它。
// content.js
DOMtoString(document); // This will be the last executed statement
function DOMtoString(document_root) { ... }
在弹出窗口中,执行脚本,收集结果:
// popup.js
// (Inside the click listener)
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.executeScript(tabs[0].id, {file: "content.js"}, function(data) {
// Data is an array of values, in case it was executed in multiple tabs/frames
download(data[0], "download.html", "text/html");
});
});
注意:以上所有内容都假设您的函数DOMtoString
实际上有效。