将消息从 background.js 传递到 popup.js

Posted

技术标签:

【中文标题】将消息从 background.js 传递到 popup.js【英文标题】:Passing message from background.js to popup.js 【发布时间】:2012-08-29 05:26:03 【问题描述】:

我正在尝试实现我自己的 chrome 扩展,在某个事件上,创建一个浏览器通知并使用在 background.js 中计算的数据填充弹出窗口

这是我的manifest.json 文件:


    "name": "Dummy name",
    "description": "Description",
    "manifest_version": 2,
    "version": "1.1.3",
    "icons": 
        "16": "icon_16.png",
        "48": "icon_48.png",
        "128": "icon_128.png",
        "256": "icon_256.png"
    ,
    "browser_action": 
        "default_icon": "icon_48.png",
        "default_title": "Test",
        "default_popup": "popup.html"
    ,
    "permissions": ["background","webRequest","webRequestBlocking","webNavigation","tabs","notifications"],
    "background": 
        "scripts":["jquery-1.8.1.min.js","classy.js","background.js"]
    

我在background.js 中给sendMessage 打电话

show : function(result) 
    var that = this;
    chrome.extension.sendMessage(greeting: "hello", function(response) 
        console.log(response);
    );

    if(window.webkitNotifications) 
        var notification = webkitNotifications.createHTMLNotification('notification.html');
        notification.show();
        setTimeout(function()
            notification.cancel();
            , '7000');
        
    

我在popup.js 中的消息监听器(来自 chrome 扩展示例)

chrome.extension.onMessage.addListener(
  function(request, sender, sendResponse) 
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.greeting == "hello")
      sendResponse(farewell: "goodbye");
  );

我得到的唯一错误是

端口错误:无法建立连接。接收端不 存在。

感谢您的帮助!

【问题讨论】:

后台页面加载很久才显示浏览器动作弹窗。显然,弹出脚本没有更改通过chrome.extension.onMessage绑定事件监听器。 如前所述,这是基于事件触发的。由于事件发生在页面加载后的几秒钟内,是否仍然可以相信它没有被弹出窗口收听? 确保你说的是真的。您可以输入一个alert('') 对话框来查看这些方法是否以预期的顺序出现。旁注,您可以通过chrome.extension.getBackgroundPage()(从弹出窗口访问后台的全局window对象)和chrome.extension.getViews(type:'popup')[0](如果存在弹出窗口的全局window对象,从背景页面)。 我刚刚对此进行了测试,实际上,弹出窗口中的任何操作都只能在它打开时触发。知道如何模拟消息发送吗?不幸的是,它与 getBackgroundPage() 和 getViews() 相同...仅在弹出窗口打开时起作用:( “显然”也已被弃用,应避免使用。 【参考方案1】:

本地存储解决方案

由于弹出窗口没有持久状态,您可能希望使用 localStorage 存储弹出窗口状态并在弹出窗口打开时预加载它,并使用storage 事件来跟踪弹出窗口打开时状态的更改。

背景:

localStorage.setItem('popupData', JSON.stringify( tabReady: true ));

弹出窗口:

// Load the state from localStorage when popup opens
let popupData = JSON.parse(localStorage.getItem('popupData'));

// Keep track of changes to the popup state while the popup is open
window.addEventListener('storage', (e) => 
  if (e.key === 'popupData') 
    popupData = JSON.parse(e.newValue);
    console.log(popupData.tabReady);
   
);

【讨论】:

【参考方案2】:

这是我发现的将数据从 background.js 发送到 popup.js 的两种最简单的方法:

1) 使用存储

将值保存到存储中,一旦弹出窗口打开,它会从存储中获取值并将它们显示在弹出窗口中。

background.js

chrome.storage.sync.set( 'dataValue1': 'Some data 1.' );
chrome.storage.sync.set( 'dataValue2': 'Some data 2.' );

popup.js

function updatePopup() 
    chrome.storage.sync.get(['dataValue1', 'dataValue2'], function (data) 
        document.getElementById("popupElement1").innerText = data.dataValue1;
        document.getElementById("popupElement2").innerText = data.dataValue2;
    );
    
document.addEventListener('DOMContentLoaded', updatePopup);

popup.html

<html>    
<head>
    <script src="popup.js"></script>
</head>    
<body>
    <p id="popupElement1"></p>
    <p id="popupElement2"></p>
</body>    
</html>

ma​​nifest.json


    "name": "Background2popup",
    "version": "1.0",
    "manifest_version": 2,
    "description": "This is a demo",
    "browser_action": 
        "default_popup": "popup.html"
    ,
    "background": 
        "scripts": [
            "background.js"
        ]
    ,
    "permissions": [
        "<all_urls>",
        "storage",
        "tabs"
    ]

2) 使用 chrome.runtime.sendMessage()

一旦弹出窗口打开,您会从弹出窗口向后台发送消息以建立连接/握手(否则,您将收到“未检查的 runtime.lastError:无法建立连接。接收端不存在。”如果您尝试从后台发送消息到弹出窗口并且弹出窗口未打开)。建立连接后,您首先使用后台的 sendResponse 将要发送的数据发送到弹出窗口。

background.js

chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) 
    if (request.method == "getStatus") 
        console.log(request.data)
        sendResponse( method: "peepee", data: "poopoo" )
    
);

popup.js

chrome.runtime.sendMessage( method: "getStatus", data: "xxx" , function (res) 
    document.getElementById("popupElement1").innerText = res.method;
    document.getElementById("popupElement2").innerText = res.data;
return true;
);

popup.html & manifest.json 与第一个示例相同

【讨论】:

【参考方案3】:

弹出窗口没有标签 ID,因此您会收到错误消息。

在这种情况下,您可以使用chrome.runtime.sendMessagechrome.runtime.onMessage.addListener

所以在 background.js

chrome.runtime.sendMessage(
    msg: "something_completed", 
    data: 
        subject: "Loading",
        content: "Just completed!"
    
);

而在 popup.js

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

希望对你有帮助。

谢谢,

【讨论】:

如果我打开了多个选项卡并向 popup.js 发送消息怎么办。哪个 popup.js 会收到它?如何将消息发送到我想发送消息的地方@Perfect 您应该将消息从弹出窗口发送到后端脚本。此时,您可以在后端脚本中获取 tab_id 来识别哪个选项卡的弹出窗口发送到后台。无法将消息从后端脚本发送到弹出窗口,但您可以将后端脚本发送到特定选项卡的内容脚本。或者您可以在后端和弹出窗口之间创建连接。看看这个链接。 ***.com/questions/13546778/… 我在看到这个之前使用 tabid 做了完全相同的事情。感谢@Perfect 提供另一种方式【参考方案4】:

要解决这个问题,您需要先向 background.js 发送握手消息,然后将实际数据从 background.js 发送到 popup.js 例如:就我而言,我所做的是

popup.js

chrome.runtime.sendMessage(data:"Handshake",function(response)
	
			);
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse)
	str = JSON.stringify(message.data);
);

background.js

chrome.runtime.onMessage.addListener(function(message,sender,sendResponse)
//alert(message.data);
	chrome.runtime.sendMessage(data:datax,function(response)
			);
			);

我试图做的是,只要我们点击图标,握手消息就会发送到 background.js,当它收到它时,我们可以发送变量或我们想要发送的任何数据到 popup.js在 popup.html 上呈现它。

【讨论】:

我喜欢握手的想法,它确保弹出窗口是活动的(没有被破坏)并且能够监听传入的数据。此外,这似乎是每个页面加载的一次性事件,它遵循 API 的 Simple one-time request methods 但这意味着调用是由Popup发起的。我相信 OP 想要从背景到弹出的对话启动。如果弹出窗口想从后台提取数据,它也可以执行以下标准方法: let bg= chrome.runtime.getBackgroundPage() 然后通过 console.log(bg.message) 获取 msg;这里的“消息”是 background.js 文件中的一个对象【参考方案5】:

使用runtime.sendMessage 将消息发送到后台脚本,使用tabs.sendMessage 从后台发送到内容脚本。

请注意,您需要指定标签ID:

chrome.tabs.query( active: true , (tabs) => 
    chrome.tabs.sendMessage(tabs[0].id,  greeting: 'hello' , (response) => 
        console.log(response);
    );
);

您可以在此处找到完整的示例和文档:https://developer.chrome.com/extensions/messaging#simple

【讨论】:

以上是关于将消息从 background.js 传递到 popup.js的主要内容,如果未能解决你的问题,请参考以下文章

Angular 6 - 通过服务将消息传递到从组件到消息组件

如何将消息从 GCP 推送订阅传递到本地 PC?

将消息从 Node.js 传递到外部系统?

将 background.js 中的数据存储到 vuex 存储中

如何将消息从 Flutter 传递到 Native?

将数据从一个 ViewController 传递到下一个时遇到问题