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

Tet*_*uth 10 javascript google-chrome google-chrome-extension

我正在搞乱(试图学习)如何制作镀铬扩展.现在我只是制作超级简单的一个,它计算页面上某个单词的实例.我有这部分工作.

我想要做的是将此信息发送到流行音乐,以便我可以用它来做其他一些事情.

这是我到目前为止:

的manifest.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"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

content.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();
Run Code Online (Sandbox Code Playgroud)

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

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

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

 chrome.runtime.sendMessage(count);
Run Code Online (Sandbox Code Playgroud)

然后在background.js中:

chrome.runtime.onMessage.addListener(
    function(response, sender, sendResponse){      
       temp = response;
    }
);
Run Code Online (Sandbox Code Playgroud)

我有点困在这里,因为我不知道如何将这些信息发送到弹出窗口并使用它.

Xan*_*Xan 47

正如您已经注意到的那样,您无法在关闭时直接将数据发送到弹出窗口.因此,您将数据发送到后台页面.

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

请注意:这个答案会先给出错误的建议,然后再改进.由于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);
        }
    }
);
Run Code Online (Sandbox Code Playgroud)

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

// 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);
        }
    }
);
Run Code Online (Sandbox Code Playgroud)

现在,这有什么问题?

  1. 一生的寿命是temp多少?您已"persistent": false在清单中明确说明.因此,可以随时卸载后台页面,擦除状态等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) {
            /* ... */
        });
    });
    
    Run Code Online (Sandbox Code Playgroud)

    虽然这是很多工作,不是吗?在修复1之后,此解决方案适用于非特定于标签的数据.


需要考虑的下一个改进:我们是否需要背景页面来存储结果?毕竟,chrome.storage是一件事 ; 它是所有扩展脚本(包括内容脚本)都可以访问的持久存储.

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

// 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
    }
});
Run Code Online (Sandbox Code Playgroud)

这看起来更干净,完全绕过了上面的问题1,但问题2变得更加棘手.你不能直接设置/读取类似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);
        }
    }
);
Run Code Online (Sandbox Code Playgroud)

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

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

现在那更清洁了.问题2解决了:我们查询我们想要听到的标签.问题1似乎得到了解决:只要脚本计算了我们需要的东西,它就可以回答.

待办事项,作为最后的并发症,这些内容脚本并不总是当你希望他们注入:他们只开始激活导航的延长是(重新)加载.这是一个非常详细解释的答案.如果你愿意,它可以解决,但现在只是它的代码路径:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 像往常一样非常彻底 (2认同)

归档时间:

查看次数:

10812 次

最近记录:

8 年,2 月 前