简体   繁体   中英

Passing data (tabs) from background.js to popup.js

I am currently trying to make a chrome extension that lists all of the open tabs in its popup window. With more functionality to be added later, such as closing a specific tab through the popup, opening up a new tab with a specific URL etc.

manifest.json

{
  "manifest_version": 2,
  "name": "List your tabs!",
  "version": "1.0.0",
  "description": "This extension only lists all of your tabs, for now.",
  "background": {
    "persistent": true,
    "scripts": [
      "js/background.js"
    ]
  },
  "permissions": [
    "contextMenus",
    "activeTab",
    "tabs"
  ],
  "browser_action": {
    "default_popup": "popup.html"
  }
}

background.js

const tabStorage = {};
(function() {

    getTabs();

    chrome.tabs.onRemoved.addListener((tab) => {
        getTabs();
    });

    chrome.tabs.onUpdated.addListener((tab) => {
        getTabs();
    });


}());

function getTabs() {
    console.clear();
    chrome.windows.getAll({populate:true},function(windows){
        windows.forEach(function(window){
            window.tabs.forEach(function(tab){
                //collect all of the urls here, I will just log them instead
                tabStorage.tabUrl = tab.url;
                console.log(tabStorage.tabUrl);
            });
        });
    });

    chrome.runtime.sendMessage({
        msg: "current_tabs", 
        data: {
            subject: "Tabs",
            content: tabStorage
        }
    });
}

popup.js

(function() {

    chrome.runtime.onMessage.addListener(
        function(request, sender, sendResponse) {
            if (request.msg === "current_tabs") {
                //  To do something
                console.log(request.data.subject)
                console.log(request.data.content)
            }
        }
    );

}());

From my understanding, since you're supposed to have listeners in background.js for any changes to your tabs. Then when those occur, you can send a message to popup.js

As you can see, for now I'm simply trying to log my tabs in the console to make sure it works, before appending it to a div or something in my popup.html . This does not work, however, because in my popup.html I'm getting the following error in the console:

popup.js:3 Uncaught TypeError: Cannot read property 'sendMessage' of undefined

so I'm... kind of understanding that I can't use onMessage in popup.js due to certain restrictions, but I also have no clue, then, on how to achieve what I'm trying to do.

Any help would be appreciated.

  1. The Google's documentation about the background script is a bit vague. The important thing for your use case is that the popup runs only when it's shown, it doesn't run when hidden, so you don't need background.js at all, just put everything in popup.js which will run every time your popup is shown, here's your popup.html:

     <script src="popup.js"></script> 
  2. The error message implies you were opening the html file directly from disk as a file:// page, but it should be opened by clicking the extension icon or via its own URL chrome-extension://id/popup.html where id is your extension's id. This happens automatically when you click the extension icon - the popup is a separate page with that URL, with its own DOM, document , window , and so on.

  3. The popup has its own devtools, see this answer that shows how to invoke it (in Chrome it's by right-clicking inside the popup, then clicking "inspect").

  4. Extension API is asynchronous so the callbacks run at a later point in the future, after the outer code has already completed, which is why you can't use tabStorage outside the callback like you do currently. More info: Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference .

  5. There should be no need to enumerate all the tabs in onRemoved and onUpdated because it may be really slow when there's a hundred of tabs open. Instead you can modify your tabStorage using the parameters provided to the listeners of these events, see the documentation for details. That requires tabStorage to hold the id of each tab so it would make sense to simply keep the entire response from the API as is. Here's a simplified example:

     let allTabs = []; chrome.tabs.query({}, tabs => { allTabs = tabs; displayTabs(); }); function displayTabs() { document.body.appendChild(document.createElement('ul')) .append(...allTabs.map(createTabElement)); } function createTabElement(tab) { const el = document.createElement('li'); el.textContent = tab.id + ': ' + tab.url; return el; } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM