Chrome Extension - 在 Background 中判斷 Popup 是否開啟中,並傳遞訊息
在 Chrome 擴充功能中,background.js 無法直接「判斷」popup.html 是否開啟中。popup.html 是在用戶點擊擴充功能圖標時才載入和執行的,關閉彈出視窗時也會卸載。
"manifest_version": 3,
"name": "My Extension",
"version": "1.0",
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"background": {
"service_worker": "background.js"
},
"permissions": [
"activeTab" // 視你的需求添加其他權限
]
}
// 監聽來自其他部分的連接
chrome.runtime.onConnect.addListener(function(port) {
if (port.name === "popup-channel") {
console.log("Popup 已連接!");
popupPort = port; // 儲存這個 port
// 監聽來自 popup 的訊息
popupPort.onMessage.addListener(function(message) {
console.log("收到來自 popup 的訊息:", message);
if (message.type === "POPUP_READY") {
// Popup 已準備好,可以回傳訊息給它
console.log("Popup 說它已經準備好了。");
// 假設 background 想要傳送一些初始數據給 popup
popupPort.postMessage({ type: "INITIAL_DATA", data: "Hello from background!" });
}
// 處理來自 popup 的其他訊息...
});
// 監聽 popup 斷開連接(即 popup 被關閉)
popupPort.onDisconnect.addListener(function() {
console.log("Popup 已斷開連接 (關閉)。");
popupPort = null; // 清除 port 引用
});
}
});
// background.js 可以在任何時候向 popup 發送訊息,只要 popupPort 存在
function sendMessageToPopup(message) {
if (popupPort) {
console.log("向 popup 發送訊息:", message);
popupPort.postMessage(message);
} else {
console.log("Popup 未開啟,無法傳送訊息。");
}
}
// 範例:在 background 某些事件發生時向 popup 發送訊息
// 例如,當用戶點擊了擴充功能圖標以外的某個內容菜單項
chrome.contextMenus.create({
id: "send-message-to-popup",
title: "傳訊息給 Popup",
contexts: ["selection"]
});
chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === "send-message-to-popup") {
sendMessageToPopup({ type: "NEW_MESSAGE", content: "這是從 background 發送的新訊息!" });
}
});
// 你也可以在其他地方調用 sendMessageToPopup,比如定時器或網路請求回調
// setTimeout(() => {
// sendMessageToPopup({ type: "REMINDER", text: "該喝水了!" });
// }, 5000);
const backgroundPort = chrome.runtime.connect({ name: "popup-channel" });
// 當 popup 載入完成時,向 background 發送訊息表示準備就緒
document.addEventListener('DOMContentLoaded', () => {
console.log("Popup DOM 已載入。");
backgroundPort.postMessage({ type: "POPUP_READY" });
});
// 監聽來自 background 的訊息
backgroundPort.onMessage.addListener(function(message) {
console.log("收到來自 background 的訊息:", message);
if (message.type === "INITIAL_DATA") {
document.getElementById('message-display').textContent = message.data;
} else if (message.type === "NEW_MESSAGE" || message.type === "REMINDER") {
const messageList = document.getElementById('message-list');
const listItem = document.createElement('li');
listItem.textContent = message.content || message.text;
messageList.appendChild(listItem);
}
// 處理其他來自 background 的訊息...
});
// 為了測試,假設 popup.html 裡有一個顯示訊息的元素
// popup.html 應該有類似 <div id="message-display"></div> 和 <ul id="message-list"></ul>
<html>
<head>
<title>My Popup</title>
<style>
body { width: 300px; padding: 10px; font-family: sans-serif; }
ul { list-style: none; padding: 0; }
li { margin-bottom: 5px; background-color: #f0f0f0; padding: 5px; border-radius: 3px; }
</style>
</head>
<body>
<h1>Popup 介面</h1>
<p>初始訊息: <span id="message-display">等待訊息...</span></p>
<h2>來自 Background 的訊息歷史:</h2>
<ul id="message-list"></ul>
<script src="popup.js"></script>
</body>
</html>
總結 background 判斷 popup 狀態的邏輯:
popupPort = null 初始狀態 :在 background.js 中,維護一個 popupPort 變數,初始為 null。onConnect 偵測 :當 popup.js 執行 chrome.runtime.connect() 時,background.js 的 chrome.runtime.onConnect 事件會被觸發。此時,popupPort 會被賦值為該連接的 port 物件。這表示 popup 已開啟。onDisconnect 偵測 :當用戶關閉彈出視窗時,popup 的 port 會自動斷開連接,background.js 的 popupPort.onDisconnect 事件會被觸發。此時將 popupPort 設置回 null。發送訊息前檢查 :當 background.js 想要向 popup 發送訊息時,只需檢查 popupPort 是否為 null。如果不是 null,則 popup 正在運行,可以安全地使用 popupPort.postMessage() 發送訊息。
留言
張貼留言