Chrome 扩展 :: 试图理解 chrome.runtime.sendmessage 到 chrome.runtime.onMessage 的语法

Chrome Extension :: Trying to understand syntax of chrome.runtime.sendmessage to chrome.runtime.onMessage

我在理解 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 中的图标上显示指标 > 用户可以在扩展程序中打开报告弹出窗口

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>

manifest.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"
    }
}

有几个小问题,我先解决一下:

background.js:

  • chrome.runtime.onMessage.addListener 缺少 =>function,具体取决于您的样式
  • 清单版本 3 中的
  • chrome.browserAction 已重命名为 chrome.action
  • 设置徽章文本时 text 属性 必须是 string 类型
  • chrome.action.setPopup 不是必需的,因为清单中已经指定了弹出窗口 (action.default_popup);使用 setPopup if/when 您希望在运行时将弹出模板动态更改为不同的模板。

content.js

  • 函数 webFunction 从未被调用,因此 sendMessage 也不会被调用

还有另一个概念性问题,涉及扩展各部分之间的数据流,以及不同部分何时 active/inactive 并且能够接收消息。看起来预期的流程是将数据从内容脚本发送到后台并或多或少同时弹出。

可以使用后台 service worker 接收来自内容的消息,然后更新徽章文本,在解决上面列出的语法问题后它会正常工作。

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

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

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

这是包含建议更改的编辑版本

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 中,我会将 <script src="popup.js"></script> 移动到 <p> 标记之后的正文末尾,因为它通过 id 查找元素,只是为了确保这些 id 存在。