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

前端 未结 1 576
臣服心动
臣服心动 2021-01-15 11:46

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

相关标签:
1条回答
  • 2021-01-15 12:21

    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.

    0 讨论(0)
提交回复
热议问题