Chrome Extension: Message Passing (Sending the DOM to popup.js) returns 'null'

故事扮演 提交于 2019-12-01 12:49:11
Xan

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

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.

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.


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).

Solution 1 (bad, but here for educational purposes)

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

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.

Solution 2

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.

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

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!