Chrome扩展程序:邮件传递(将DOM发送到popup.js)返回' null'

时间:2014-12-15 05:01:13

标签: javascript dom google-chrome-extension message-passing

我想使用Chrome扩展程序下载当前页面的DOM。我不确定原因,但是当我下载时,结果只是一个文本文件,其中包含&#39; null&#39;或者&#39; undefined&#39;而不是DOM。我试图吸收来自herehere的知识,但我似乎无法从content.jspopup.js收到消息。< / p>

此外,我不确定为什么this确实有效。当我阅读docs时,似乎我需要通过选择有效标签将消息从popup.js发送到content.js

chrome.tabs.query({currentWindow: true, active: true}, function(tabs) {
    chrome.tabs.sendMessage(tabs[0].id, {message: 'getMessageFromContent'}, function(response) {
        //Code to handle response from content.js
    }
});

我目前的代码:

content.js

var page_html = DOMtoString(document);
chrome.runtime.sendMessage({method: 'downloadPageDOM', pageDOM: thisPage});

function DOMtoString(document_root) { ... }

background.js

chrome.tabs.query({currentWindow: true, active: true}, function(tab) {
    var page_html;
    chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
        if (request.message == 'downloadPageDOM')
            page_html = request.pageDOM;
        else if (request.message == 'getPageDOM')
            sendResponse(page_html);
    });
}); 

popup.js

document.addEventListener('DOMContentLoaded', function() {
    var download_button = document.getElementById('download_button');
    download_button.addEventListener('click', function() {
        chrome.runtime.sendMessage({message:'getPageDOM'}, function(response) {
            download(response, "download.html", "text/html");
        });
    });
});

function download(data, fileName, mimeType) { ... }

我觉得我错过了对消息传递如何工作的重要理解。如果有人可以花一点时间来帮助我理解为什么下载的文件只有&#39; null&#39;,我会非常感激。

1 个答案:

答案 0 :(得分:2)

你过度复杂,导致很多逻辑错误。

您已将背景页面设置为充当消息代理,内容脚本本身会触发更新page_html变量。然后弹出窗口会用另一条消息拉出该数据。

请注意,page_html在任何情况下都不会包含当前标签的数据:您使用上一个加载的标签覆盖了此数据。


你能做的就是完全切断中间人(即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%健壮。如果内容脚本未注入页面(and this can happen),则会失败。但是可以解决这个问题。

解决方案2

我们不假设注入了内容脚本。事实上,大多数情况下,只有当用户点击你的按钮时,你才不需要自动注入它。

因此,请从清单中删除内容脚本,确保host permissions"<all_urls>"运行良好,但考虑activeTab permission),并使用programmatic injection。< / p>

有一种很少使用的编程注入形式,它收集最后执行的语句的值。我们打算用它。

// 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确实有效。