Chrome扩展:消息传递(将DOM发送到popup.js)返回'null' [英] Chrome Extension: Message Passing (Sending the DOM to popup.js) returns 'null'

查看:173
本文介绍了Chrome扩展:消息传递(将DOM发送到popup.js)返回'null'的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用Chrome扩展程序来下载当前页面的DOM。我不知道为什么,但是当我的下载发生时,结果只是一个文本文件,具有'null'或'undefined',而不是DOM。我试图吸收这里的知识。 a>和此处 ,但我似乎无法从 content.js popup.js

I would like to use a Chrome Extension to download the current page's DOM. I'm not sure why, but when my download occurs, the result is just a text file with either 'null' or 'undefined', rather than the DOM. I've tried to assimilate the knowledge from here and here, but I can't seem to get the message from content.js through to popup.js.

此外,我不知道为什么这个实际上是有效的。当我阅读文档时,似乎我需要从 popup.js to content.js 通过选择活动标签:

Additionally, I'm not sure why this actually works. When I read the docs, it seems like I need to send the message from popup.js to content.js by selecting the active tab:

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
    }
});






我目前的代码:


My current code:

内容。 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,那么我真诚的感谢。

I feel like I'm missing a crucial understanding of how message passing works. If anyone could take a second to help me understand why the file that downloads just has 'null', I would sincerely appreciate it.

推荐答案

p>你过度复杂了,这导致了很多逻辑错误。

You're over-complicating this, which leads to a lot of logical errors.

你已经设置了背景页面,就像一个消息代理一样,内容脚本本身会触发更新您的 page_html 变量。然后,该弹出窗口使用另一个消息提取数据。

You've set up the background page to act like a message proxy, and the content script itself triggers updating your page_html variable. Then the popup pulls that data with another message.

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

Note that page_html will not contain the current tab's data in any case: you're overwriting this data with the last loaded tab.

你可以做的是完全删除中间人(即 background.js )。我想你感到困惑的是,向弹出窗口发送消息通常是一个坏主意(不保证它是开放的),但是另一种方式通常是安全的(并且您可以使其永远安全)。

What you can do is completely cut out the middleman (i.e. background.js). I guess you got confused by the fact that sending a message TO a popup is a generally a bad idea (no guarantee it's open), but the other way around is usually safe (and you can make it always safe).

您的应用程序的逻辑是:一旦用户点击按钮,在那个时刻制作快照。所以,不要让你的内容脚本立即执行,添加一个消息监听器:

The logic of your app is: once the user clicks the button, make the snapshot at that moment. So, instead of making your content script do its work immediately, add a message listener:

// content.js
chrome.runtime.onMessage(function(message, sender, sendResponse) {
  else if (request.message == 'getPageDOM')
    sendResponse(DOMtoString(document));
});

function DOMtoString(document_root) { ... }

在你的弹出窗口,请求:

And in your popup, request it:

// 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%稳健的。如果内容脚本未注入到页面(并且可能会发生),则会失败。但是可以解决这个问题。

However, this solution is not 100% robust. It will fail if the content script is not injected into the page (and this can happen). But it's possible to fix this.

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

Let's not assume the content script is injected. In fact, most of the time you don't NEED to inject it automatically, only when the user clicks your button.

所以,从清单中删除内容脚本,请确保您有主机权限< all_urls>的效果很好,尽管考虑到 activeTab 权限),以及使用编程注入

So, remove the content script from the manifest, make sure you have host permissions ("<all_urls>" works well, though consider activeTab permission), and the use programmatic injection.

程序化注入有一点点使用形式,用于收集上一次执行语句的值。我们要使用它。

There is a little-used form of programmatic injection that collects the value of the last executed statement. We're going to use that.

// content.js
DOMtoString(document); // This will be the last executed statement

function DOMtoString(document_root) { ... }

在弹出窗口中,执行脚本,收集结果:

In the popup, execute script, collect results:

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


NOTE: All of the above assumes that your function DOMtoString actually works.

这篇关于Chrome扩展:消息传递(将DOM发送到popup.js)返回'null'的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆