javascript - 将变量从内容脚本传递到弹出窗口

标签 javascript google-chrome google-chrome-extension

我正在研究(尝试学习)如何制作 chrome 扩展程序。现在我只是做一个 super 简单的,它计算页面上某个单词的实例。我有这部分工作。

我想做的是将此信息发送给 pop,这样我就可以用它来做一些其他事情。

这是我目前所拥有的:

list .json

{
    "manifest_version": 2,
    "name": "WeedKiller",
    "description": "Totally serious $100% legit extension",
    "version": "0.1",

    "background": {
        "persistent": false,
        "scripts": ["background.js"]
    },

    "permissions":[
        "tabs",
        "storage"
    ],
    "browser_action": {
    "default_icon": "icon.png",
    "default_title": "WeedKiller",
    "default_popup": "popup.html"
    },
    "content_scripts": [
        {
            "matches": [
                "http://*/*",
                "https://*/*"
            ],
            "js": [
                "content.js"
            ],
            "run_at": "document_end"
        }
    ]
}

内容.js

var elements = document.getElementsByTagName('*');
var count = 0;

function tokeCounter(){
    for (var i = 0; i < elements.length; i++) {
        var element = elements[i];

        for (var j = 0; j < element.childNodes.length; j++) {
            var node = element.childNodes[j];

            if (node.nodeType === 3) {
                var text = node.nodeValue;
                if(text == '420'){
                    count++; 
                }

                var replacedText = text.replace(/420/, '+1');

                if (replacedText !== text) {
                    element.replaceChild(document.createTextNode(replacedText), node);
                }
            }
        }    
    }
}

tokeCounter();

所以我想要发生的是将 count 变量发送到弹出窗口,以便我可以在那里使用它。

我环顾四周,发现我需要用 chrome.runtime.sendMessage 做点什么。

我有它,所以我将这一行添加到 content.js 的末尾:

 chrome.runtime.sendMessage(count);

然后在 background.js 中:

chrome.runtime.onMessage.addListener(
    function(response, sender, sendResponse){      
       temp = response;
    }
);

我有点卡在这里,因为我不确定如何将此信息发送到弹出窗口并使用它。

最佳答案

您已经注意到,当弹出窗口关闭时,您无法将数据直接发送到该弹出窗口。因此,您正在向后台页面发送数据。

然后,您打开弹出窗口时,您需要那里的数据。那么,有哪些选择呢?

请注意:这个回答会先给出不好的建议,然后再改进。由于 OP 正在学习,因此展示思维过程和路障很重要。


想到的第一个解决方案如下:询问后台页面,再次使用 Messaging。 预警:这将不起作用或效果不佳

首先,确定可以有不同类型的消息。修改您当前的消息代码:

// content.js
chrome.runtime.sendMessage({type: "setCount", count: count});

// background.js
chrome.runtime.onMessage.addListener(
    function(message, sender, sendResponse) {
        switch(message.type) {
            case "setCount":
                temp = message.count;
                break;
            default:
                console.error("Unrecognised message: ", message);
        }
    }
);

现在,理论上您可以在弹出窗口中询问:

// popup.js
chrome.runtime.sendMessage({type: "getCount"}, function(count) {
    if(typeof count == "undefined") {
        // That's kind of bad
    } else {
        // Use count
    }
});

// background.js
chrome.runtime.onMessage.addListener(
    function(message, sender, sendResponse) {
        switch(message.type) {
            case "setCount":
                temp = message.count;
                break;
            case "getCount":
                sendResponse(temp);
                break;
            default:
                console.error("Unrecognised message: ", message);
        }
    }
);

现在,这有什么问题?

  1. temp 的生命周期是多少?您已明确说明 "persistent": false in your manifest .因此,后台页面可以随时卸载,删除 temp 等状态。

    您可以使用 "persistent": true 修复它,但请继续阅读。

  2. 您希望看到哪个选项卡的计数? temp 将写入最后的数据,这很可能不是当前选项卡。

    您可以通过保持选项卡(看看我在那里做了什么?)来修复它,在哪个选项卡上发送了数据,例如通过使用:

    // background.js
    /* ... */
      case "setCount":
          temp[sender.tab.id] = message.count;
          break;
      case "getCount":
          sendResponse(temp[message.id]);
          break;
    
    // popup.js
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
        // tabs is a single-element array after this filtering
        chrome.runtime.sendMessage({type: "getCount", id: tabs[0].id}, function(count) {
            /* ... */
        });
    });
    

    虽然工作量很大,不是吗? 修复 1 后,此解决方案适用于非特定于选项卡的数据。


下一步要考虑的改进:我们是否需要后台页面来为我们存储结果?毕竟,chrome.storage is a thing ;它是所有扩展脚本(包括内容脚本)都可以访问的持久存储。

这会从图片中删除背景(和消息):

// content.js
chrome.storage.local.set({count: count});

// popup.js
chrome.storage.local.get("count", function(data) {
    if(typeof data.count == "undefined") {
        // That's kind of bad
    } else {
        // Use data.count
    }
});

这看起来更清晰,并且完全绕过了上面的问题 1,但问题 2 变得更加棘手。 You can't directly set/read像存储中的count[id],你需要读出count,修改它并写回。它可能会变得缓慢而困惑。

此外,内容脚本并不真正知道它们的标签 ID;您需要向背景发送消息才能了解它。啊。不漂亮。 同样,对于非特定于选项卡的数据,这是一个很好的解决方案。


那么下一个问题要问:为什么我们甚至需要一个中心位置来存储(特定于选项卡的)结果?内容脚本的生命周期就是页面的生命周期。您可以随时直接询问内容脚本。包括来自弹出窗口。

等等,您不是在最上面说过不能向弹出窗口发送数据吗? 嗯,是的,有点:当您不这样做时不知道它是否在那里听。但如果弹出窗口询问,那么它必须准备好获得响应,不是吗?

那么,让我们反转内容脚本逻辑。不要立即发送数据,而是等待并监听请求:

chrome.runtime.onMessage.addListener(
    function(message, sender, sendResponse) {
        switch(message.type) {
            case "getCount":
                sendResponse(count);
                break;
            default:
                console.error("Unrecognised message: ", message);
        }
    }
);

然后,在弹出窗口中,我们需要查询包含内容脚本的选项卡。这是一个不同的消息功能,我们必须指定选项卡 ID。

    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
        chrome.tabs.sendMessage(tabs[0].id, {type: "getCount"}, function(count) {
            /* ... */
        });
    });

现在更清晰了。问题 2 已解决:我们查询我们想要收听的选项卡。问题1好像解决了:一个脚本只要统计我们需要的就可以回答。

请注意,作为最后一个复杂因素,内容脚本并不总是在您期望的时候注入(inject):它们只会在扩展被(重新)加载后 开始在导航上激活。这是 an answer非常详细地解释了这一点。如果您愿意,可以解决它,但现在只是一个代码路径:

function(count) {
    if(typeof count == "undefined") {
        // That's kind of bad
        if(chrome.runtime.lastError) {
            // We couldn't talk to the content script, probably it's not there
        }
    } else {
        // Use count
    }
}

关于javascript - 将变量从内容脚本传递到弹出窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31111721/

相关文章:

javascript - 通过 Typeahead.js 提供建议

javascript - 如何对 CSS 自定义属性进行特征检测?

javascript - iframe设计模式下光标移动问题

javascript - JavaScript 中的原型(prototype)不好吗?

javascript - 是否有相当于 ios 自动布局约束概念的 JavaScript 或 Web 开发库?

google-chrome - 如何仅向测试人员发布新版本的 Chrome 扩展

java - Native Messaging 主机尝试发送长度为 977472013 字节的消息

javascript - 使用 Chrome Tabs API 单击按钮打开选项卡

javascript - 在 Chrome 扩展中写入本地文件系统

javascript - 如何将调试器附加到设备? Chrome 扩展