【问题标题】:Chrome Extension :: Trying to understand syntax of chrome.runtime.sendmessage to chrome.runtime.onMessageChrome 扩展 :: 试图理解 chrome.runtime.sendmessage 到 chrome.runtime.onMessage 的语法
【发布时间】:2021-12-01 12:06:16
【问题描述】:

我在理解 chrome.runtime.sendmessage 如何将数据从我的 Content.js 文件发送到我的 chrome.runtime.onMessage Background.js 文件的语法时遇到了一些问题。我正在尝试注入一个脚本来查看网页指标并在导航到新页面时在 Chrome 扩展弹出窗口中显示它们。我无法看到从我的 content.js 脚本发送到我的 background.js 脚本的变量。我不需要在会话之间缓存数据,只希望我的脚本在用户所在的当前选项卡中运行。

我的 Content.js 脚本应该使用 Manifest.js 中的 "run_at": "document_idle" 执行。

Content.js 运行 > setBadgeAction 在 Background.js 的图标上显示指标 > 用户可以在扩展程序 Popup

中打开报告

Background.js:

chrome.runtime.onMessage.addListener((request, sender, sendResponse){
    chrome.browserAction.setBadgeText({
                        text: request.apple,
                        tabId: sender.tab.id
                    });
                    chrome.browserAction.setPopup({
                        tabId: sender.tab.id,
                        popup: "popup.html"
                    });
               });

content.js:

function webFunction(){

var apple = 0;
var orange = 3;
var kiwi = 5;
var banana = 13;

chrome.runtime.sendMessage({
    apple: apple,
    orange: orange,
    kiwi: kiwi,
    banana: banana,    
            });
}

popup.js

chrome.tabs.query({
        active: true,
        currentWindow: true
    });
chrome.runtime.onMessage.addListener((request,sender) =>{
            
document.getElementById("appleTag").innerHTML = request.apple;
document.getElementById("orangeTag").innerHTML = request.orange;
document.getElementById("kiwiTag").innerHTML = request.kiwi;
document.getElementById("bananaTag").innerHTML = request.banana;
});

popup.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="popup.css">
<script src="popup.js"></script>
</head>
<body>

<p id ="appleTag">Apple Score</p>
<p id ="orangeTag">Orange Score</p>
<p id ="kiwiTag">Kiwi Score</p>
<p id ="bananaTag">Banana Score</p>
</body>
</html>

ma​​nifest.js

{
  "name": "",
  "description": "",
  "version": "1.0",
  "manifest_version": 3,
  "action":{
        "default_popup": "popup.html",
        "default_icon": {
            "16": "/images/16.png",
            "32": "/images/32.png",
            "48": "/images/48.png",
            "128": "/images/128.png"
        }
    },
  "content_scripts": [
        {
            "matches": [
                "*://*/*"
            ],
            "run_at": "document_idle",
            "js": [
                "content.js"
            ]
        }
      ],
  "options_page": "popup.html", 
  "background": {
    "service_worker": "background.js"
},
// Permissions for the Extension.    
  "permissions": [
      "storage", 
    "activeTab" 
],
"icons": {
      "16": "/images/16.png",
      "32": "/images/32.png",
      "48": "/images/48.png",
      "128": "/images/128.png"
    }
}

【问题讨论】:

    标签: javascript html google-chrome google-chrome-extension firefox-addon-webextensions


    【解决方案1】:

    有几个小问题,我将首先解决:

    background.js:

    • chrome.runtime.onMessage.addListener 缺少 =&gt;function,具体取决于您的风格
    • 清单版本 3 中的 chrome.browserAction 已重命名为 chrome.action
    • 设置徽章文本时,text 属性必须为 string 类型
    • chrome.action.setPopup 不是必需的,因为清单中已经指定了弹出窗口(@98​​7654332@);如果/当您想在运行时将弹出模板动态更改为不同的模板时,请使用 setPopup

    content.js

    • 函数webFunction 永远不会被调用,所以sendMessage 也不会被调用

    还有另一个概念问题,与扩展部分之间的数据流有关,以及不同部分何时处于活动/非活动状态并能够接收消息。看起来预期的流程是将数据从内容脚本发送到后台并或多或少地同时弹出。

    后台Service Worker可用于接收来自内容的消息,然后更新徽章文本,在解决上述语法问题后它将正常工作。

    当用户物理点击扩展图标并且弹出窗口打开时,弹出窗口处于活动状态。弹出窗口失去焦点后,它将在用户下次单击扩展图标时被回收并重新加载。当用户专注于选项卡并运行内容脚本时,弹出窗口无法同时打开,因此无法接收消息。

    为了将数据传递给弹出窗口,您需要一些中介从内容中接收数据,然后在弹出窗口加载并准备好接收它时将其提供给弹出窗口。在清单 V2 中,出于此目的使用后台(可能)是合理的,因为它不打算长时间存储,但在 MV3 中,后台服务工作人员是短暂的,一段时间后它会变得不活跃。由于这个原因,即使是暂时的,它也不能作为保存数据的可靠中介。你可以找到一些关于这个话题的官方讨论here

    为了达到预期的行为,我建议使用storage API。这将允许在内容脚本中捕获数据,并在弹出窗口准备好加载时恢复弹出窗口中的相同数据。这可能已经是意图,因为存储包含在清单权限中,这是必需的。您可能需要考虑使用一些查找键从每个特定选项卡的存储中获取数据,如果在这方面计数会有所不同,则在选项卡/窗口/浏览器关闭时清除存储数据。

    这是一个带有建议更改的编辑版本

    content.js

    // removed webFunction declaration
     
    var apple = 0;
    var orange = 3;
    var kiwi = 5;
    var banana = 13;
    var counts = {apple, orange, kiwi, banana}
    
    chrome.storage.local.set(counts);   // persist data
    chrome.runtime.sendMessage(counts); // send to background
    

    background.js

    chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
        if (request.apple !== undefined) // null check before setting badge
            chrome.action.setBadgeText({
                text: request.apple.toString(),
                tabId: sender.tab.id
            });
    });
    

    popup.js

    // get counts from storage; null means "get everything"
    chrome.storage.local.get(null, request => {
        document.getElementById("appleTag").innerHTML = request.apple;
        document.getElementById("orangeTag").innerHTML = request.orange;
        document.getElementById("kiwiTag").innerHTML = request.kiwi;
        document.getElementById("bananaTag").innerHTML = request.banana;
    });
    

    在 popup.html 中,我会将 &lt;script src="popup.js"&gt;&lt;/script&gt; 移动到 &lt;p&gt; 标记之后的正文末尾,因为它通过 id 查找元素,只是为了确保这些 id 存在。

    【讨论】:

    • 感谢这有很大帮助!消息灵通,并帮助我了解了我在其他回复中看到的其他一些概念。我将如何格式化以获取每个选项卡的数据?现在,我只是在刷新最新页面后打开的每个选项卡看到相同的报告。
    • 在存储数据时,添加一个键,例如tab id,然后通过tab id查找数据,使其对每个tab都是唯一的。
    • 仍在努力。我有几个问题。 1) 我的 pop.js 中需要这样的东西吗?: chrome.tabs.query({ active: true, currentWindow: true }) .then(tabs => { var tab = tabs[0]; chrome.storage .local.get('cache') .then(data => { var value = data.cache['tab' + tab.id]; var appleViewer = value.apple; document.getElementById("appleHTML").innerHTML =苹果浏览器 }); }); 2) 发送:chrome.storage.local.set(counts(tab.id)); ?
    • 是的,你走在正确的轨道上,但是打开一个关于如何按标签保存数据的新问题,如果你遇到困难,还可能在不再需要数据时如何清除它。我可以找到类似的问题(例如stackoverflow.com/questions/55272272/…)但不是很好的答案。
    • 很高兴我不是唯一一个这么想的人。会的-谢谢。
    猜你喜欢
    • 2015-04-21
    • 2017-05-02
    • 2015-10-15
    • 1970-01-01
    • 1970-01-01
    • 2018-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多