【问题标题】:Chrome Extension: Message Passing (Sending the DOM to popup.js) returns 'null'Chrome 扩展:消息传递(将 DOM 发送到 popup.js)返回“null”
【发布时间】:2015-02-13 04:06:17
【问题描述】:

我想使用 Chrome 扩展程序来下载当前页面的 DOM。我不知道为什么,但是当我下载时,结果只是一个带有“null”或“undefined”的文本文件,而不是 DOM。我试图吸收来自herehere 的知识,但我似乎无法从content.jspopup.js 获取信息。

此外,我不确定为什么 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) { ... }

我觉得我缺少对消息传递如何工作的重要理解。如果有人能花点时间帮助我理解为什么下载的文件只有“null”,我将不胜感激。

【问题讨论】:

  • 调用chrome.tabs.query背后的逻辑是什么?你没有使用响应。

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


【解决方案1】:

您过于复杂了,这会导致很多逻辑错误。

您已将后台页面设置为充当消息代理,并且内容脚本本身会触发更新您的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

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

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

【讨论】:

  • 非常感谢您的帮助。我认为阅读所有文档后,我的脑海中塞满了很多信息,但没有真正的地图可以使用它。你的两个例子真的帮助我理解了发生了什么。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-01
  • 1970-01-01
相关资源
最近更新 更多