// 存储消息处理器的数组
let messageHandlers = [];
// 设置消息监听器
const setupMessageListener = () => {
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log('Received message:', message, 'from sender:', sender);
// 调用所有注册的消息处理器
handleMessage(message, sender, sendResponse);
return true; // 保持响应通道打开
});
};
// 处理接收到的消息
const handleMessage = (message, sender, sendResponse) => {
if (messageHandlers) {
messageHandlers.forEach((handler) => {
handler(message, sender, sendResponse);
});
}
};
// 发送运行时消息
const sendRuntimeMessage = (message, callback) => {
console.log('Sending runtime message:', message);
chrome.runtime.sendMessage(message, (response) => {
console.log('Received runtime response:', response);
if (callback) {
callback(response);
}
});
};
// 向指定标签发送消息
const sendTabMessage = (tabId, message, callback) => {
console.log(`Sending message to tab ${tabId}:`, message);
chrome.tabs.sendMessage(tabId, message, (response) => {
console.log(`Received response from tab ${tabId}:`, response);
if (callback) {
callback(response);
}
});
};
// 注册消息处理器
const registerMessageHandler = (handler) => {
if (!messageHandlers) {
messageHandlers = [];
}
messageHandlers.push(handler);
};
// 向所有标签发送消息
const sendMessageToAllTabs = (message, callback) => {
chrome.tabs.query({}, (tabs) => {
tabs.forEach((tab) => {
sendTabMessage(tab.id, message, callback);
});
});
};
// 向活动标签发送消息
const sendMessageToActiveTab = (message, callback) => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs.length > 0) {
sendTabMessage(tabs[0].id, message, callback);
}
});
};
// 向背景页发送消息
const sendMessageToBackground = (message, callback) => {
sendRuntimeMessage(message, callback);
};
// 向内容脚本发送消息
const sendMessageToContentScript = (tabId, message, callback) => {
sendTabMessage(tabId, message, callback);
};
// 从内容脚本发送消息到后台
const sendMessageFromContentScriptToBackground = (message, callback) => {
sendRuntimeMessage(message, callback);
};
// 从后台发送消息到内容脚本
const sendMessageFromBackgroundToContentScript = (tabId, message, callback) => {
sendTabMessage(tabId, message, callback);
};
// 初始化消息监听器
setupMessageListener();
// 导出所有方法
export {
sendRuntimeMessage,
sendTabMessage,
registerMessageHandler,
sendMessageToAllTabs,
sendMessageToActiveTab,
sendMessageToBackground,
sendMessageToContentScript,
sendMessageFromContentScriptToBackground,
sendMessageFromBackgroundToContentScript
};
sendRuntimeMessage
在 Chrome 扩展中,当需要在不同组件(如弹出页、后台脚本、内容脚本等)之间进行通信时,如果不涉及特定标签页,就可以使用 sendRuntimeMessage
。例如,弹出页需要向后台脚本发送请求,获取一些全局信息。
用户打开 Chrome 扩展的弹出页,点击某个按钮,弹出页需要向后台脚本发送一个请求,获取当前扩展的配置信息。
// 弹出页脚本 (popup.js)
import { sendRuntimeMessage } from './communicator.js';
document.querySelector('#getConfigButton').addEventListener('click', () => {
sendRuntimeMessage({ action: 'getConfig' }, (response) => {
console.log('Received config:', response);
});
});
// 后台脚本 (background.js)
import { registerMessageHandler } from './communicator.js';
registerMessageHandler((message, sender, sendResponse) => {
if (message.action === 'getConfig') {
const config = { theme: 'dark', notifications: true };
sendResponse(config);
}
return true;
});
sendTabMessage
当需要向特定的标签页发送消息时,例如在后台脚本中,根据用户的操作向某个指定的标签页发送消息,让该标签页的内容脚本执行相应的操作。
用户在扩展的管理界面选择了一个特定的标签页,然后点击“刷新内容”按钮,后台脚本需要向该标签页发送消息,让内容脚本刷新页面上的特定内容。
// 后台脚本 (background.js)
import { sendTabMessage } from './communicator.js';
// 假设 tabId 是目标标签页的 ID
const tabId = 123;
sendTabMessage(tabId, { action: 'refreshContent' }, (response) => {
console.log('Response from tab:', response);
});
// 内容脚本 (content.js)
import { registerMessageHandler } from './communicator.js';
registerMessageHandler((message, sender, sendResponse) => {
if (message.action === 'refreshContent') {
// 刷新页面内容的逻辑
console.log('Refreshing content...');
sendResponse({ status: 'Content refreshed' });
}
return true;
});
registerMessageHandler
用于注册一个回调函数,当接收到消息时,该回调函数会被调用。可以在不同的脚本(如后台脚本、内容脚本、弹出页脚本)中使用,以处理接收到的消息。
在内容脚本中,需要处理来自后台脚本或其他组件的消息,通过注册消息处理函数,当接收到特定类型的消息时,执行相应的操作。
// 内容脚本 (content.js)
import { registerMessageHandler } from './communicator.js';
registerMessageHandler((message, sender, sendResponse) => {
if (message.action === 'showAlert') {
alert(message.data);
sendResponse({ status: 'Alert shown' });
}
return true;
});
sendMessageToAllTabs
当需要向所有打开的标签页发送消息时,例如在后台脚本检测到某个全局事件(如网络状态变化),需要通知所有标签页的内容脚本更新界面。
用户的网络连接从离线变为在线,后台脚本检测到这个变化后,需要通知所有打开的标签页的内容脚本,让它们更新页面上的网络状态提示。
// 后台脚本 (background.js)
import { sendMessageToAllTabs } from './communicator.js';
window.addEventListener('online', () => {
sendMessageToAllTabs({ action: 'networkOnline' }, (response) => {
console.log('Response from tab:', response);
});
});
// 内容脚本 (content.js)
import { registerMessageHandler } from './communicator.js';
registerMessageHandler((message, sender, sendResponse) => {
if (message.action === 'networkOnline') {
const statusElement = document.getElementById('network-status');
if (statusElement) {
statusElement.textContent = 'Online';
}
sendResponse({ status: 'Status updated' });
}
return true;
});
sendMessageToActiveTab
当需要向当前活动的标签页发送消息时,例如用户点击扩展的某个功能按钮,需要让当前活动标签页的内容脚本执行相应操作。
用户在扩展的弹出页点击“高亮链接”按钮,扩展需要向当前活动的标签页发送消息,让内容脚本将页面上的所有链接高亮显示。
// 弹出页脚本 (popup.js)
import { sendMessageToActiveTab } from './communicator.js';
document.querySelector('#highlightLinksButton').addEventListener('click', () => {
sendMessageToActiveTab({ action: 'highlightLinks' }, (response) => {
console.log('Response from active tab:', response);
});
});
// 内容脚本 (content.js)
import { registerMessageHandler } from './communicator.js';
registerMessageHandler((message, sender, sendResponse) => {
if (message.action === 'highlightLinks') {
const links = document.querySelectorAll('a');
links.forEach((link) => {
link.style.backgroundColor = 'yellow';
});
sendResponse({ status: 'Links highlighted' });
}
return true;
});
sendMessageToBackground
当内容脚本或弹出页脚本需要与后台脚本进行通信时,可以使用该方法。例如,内容脚本检测到页面上的特定元素被加载,需要通知后台脚本进行记录。
用户打开一个网页,内容脚本检测到页面上的某个特定广告元素被加载,需要通知后台脚本记录该广告的相关信息。
// 内容脚本 (content.js)
import { sendMessageToBackground } from './communicator.js';
const adElement = document.getElementById('specific-ad');
if (adElement) {
sendMessageToBackground({ action: 'adLoaded', adId: 'ad123' }, (response) => {
console.log('Response from background:', response);
});
}
// 后台脚本 (background.js)
import { registerMessageHandler } from './communicator.js';
registerMessageHandler((message, sender, sendResponse) => {
if (message.action === 'adLoaded') {
console.log(`Ad ${message.adId} was loaded.`);
sendResponse({ status: 'Ad info recorded' });
}
return true;
});
sendMessageToContentScript
后台脚本或其他组件需要向特定标签页的内容脚本发送消息时使用。例如,后台脚本在定时任务中需要通知某个标签页的内容脚本进行数据更新。
后台脚本有一个定时任务,每隔一段时间需要通知特定标签页的内容脚本更新页面上的股票价格数据。
// 后台脚本 (background.js)
import { sendMessageToContentScript } from './communicator.js';
// 假设 tabId 是目标标签页的 ID
const tabId = 456;
setInterval(() => {
sendMessageToContentScript(tabId, { action: 'updateStockPrices' }, (response) => {
console.log('Response from content script:', response);
});
}, 60000);
// 内容脚本 (content.js)
import { registerMessageHandler } from './communicator.js';
registerMessageHandler((message, sender, sendResponse) => {
if (message.action === 'updateStockPrices') {
// 更新股票价格数据的逻辑
console.log('Updating stock prices...');
sendResponse({ status: 'Stock prices updated' });
}
return true;
});
sendMessageFromContentScriptToBackground
内容脚本在页面上检测到某些事件或状态变化时,需要通知后台脚本进行处理。例如,内容脚本检测到用户在页面上进行了特定的操作,需要通知后台脚本记录日志。
用户在网页上填写表单并提交,内容脚本检测到表单提交事件,需要通知后台脚本记录用户的操作信息。
// 内容脚本 (content.js)
import { sendMessageFromContentScriptToBackground } from './communicator.js';
const form = document.querySelector('form');
if (form) {
form.addEventListener('submit', () => {
sendMessageFromContentScriptToBackground({ action: 'formSubmitted', formData: { name: 'John', age: 30 } }, (response) => {
console.log('Response from background:', response);
});
});
}
// 后台脚本 (background.js)
import { registerMessageHandler } from './communicator.js';
registerMessageHandler((message, sender, sendResponse) => {
if (message.action === 'formSubmitted') {
console.log('Form submitted with data:', message.formData);
sendResponse({ status: 'Form submission logged' });
}
return true;
});
sendMessageFromBackgroundToContentScript
后台脚本在处理一些逻辑后,需要向特定标签页的内容脚本发送消息,让内容脚本执行相应的操作。例如,后台脚本接收到服务器的更新通知,需要通知某个标签页的内容脚本更新页面显示。
后台脚本接收到服务器推送的新消息通知,需要向特定标签页的内容脚本发送消息,让内容脚本在页面上显示新消息提示。
// 后台脚本 (background.js)
import { sendMessageFromBackgroundToContentScript } from './communicator.js';
// 假设 tabId 是目标标签页的 ID
const tabId = 789;
// 模拟接收到服务器新消息通知
function onNewMessageReceived() {
sendMessageFromBackgroundToContentScript(tabId, { action: 'showNewMessage', message: 'You have a new message!' }, (response) => {
console.log('Response from content script:', response);
});
}
// 内容脚本 (content.js)
import { registerMessageHandler } from './communicator.js';
registerMessageHandler((message, sender, sendResponse) => {
if (message.action === 'showNewMessage') {
const notificationElement = document.createElement('div');
notificationElement.textContent = message.message;
document.body.appendChild(notificationElement);
sendResponse({ status: 'New message notification shown' });
}
return true;
});