admin管理员组文章数量:1130349
前言
前面我们介绍了Chrome插件中存在的4种JS,那么它们之间如何互相通信呢?
1. Chrome插件的5种类型的JS对比
| JS种类 | content script | service worker | popup | devtools |
|---|---|---|---|---|
| 可访问的API | 只能访问dom、i18n、storage、runtime等部分API | 可访问绝大部分API,除了devtools系列 | 可访问绝大部分API,除了devtools系列 | 只能访问 devtools、runtime等部分API |
| DOM访问情况 | 页面DOM | 无 | 弹窗DOM | 页面DOM |
| 生命周期 | 随页面加载/卸载 | 按需唤醒,最长 5 分钟(和V2版本插件有区别) | 随弹窗打开/关闭 | 随 DevTools 打开/关闭 |
| 典型用途 | 修改页面内容、监控用户交互 | 跨标签管理、定时任务、消息路由 | 快速操作入口、状态展示 | 开发者工具集成、调试工具开发 |
2. 消息通信
2.1 popup.js和service-worker.js
弹出页面(popup.js) 和 背景脚本(service-worker.js) 之间的通信通常通过 chrome.runtime.sendMessage 来实现。
popup.js向service-worker.js发送消息
// service-worker.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
if (message.type === 'popupSendMessageToServiceWorker') {
sendResponse({ success: true, message: 'service-worker.js收到消息' });
}
});
// popup.js
chrome.runtime.sendMessage({ type: 'popupSendMessageToServiceWorker' }, function(response) {
console.log(response); // 输出从service-worker.js返回的数据
});
service-worker.js向popup.js发送消息(因为popup.js的生命周期随弹窗打开才开始,所以演示代码里,service-worker.js加了延时发消息)
// popup.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
if (message.type === 'serviceWorkerSendMessageToPopup') {
sendResponse({ success: true, message: 'popup.js收到消息' });
}
});
// service-worker.js
setTimeout(function () {
chrome.runtime.sendMessage({type: 'serviceWorkerSendMessageToPopup'}, function (response) {
console.log(response); // 输出从popup.js返回的数据
})
},
5000
);
2.2 content.js和service-worker.js
content.js 和 service-worker.js 通常通过 chrome.runtime.sendMessage 或 chrome.tabs.sendMessage 进行消息传递。
content.js向service-worker.js发送消息
// service-worker.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
if (message.type === 'contentSendMessageToServiceWorker') {
sendResponse({ success: true, message: 'service-worker.js收到消息' });
}
});
// content.js
chrome.runtime.sendMessage({ type: 'contentSendMessageToServiceWorker' }, function(response) {
console.log(response);
});
service-worker.js向content.js发送消息(演示代码里service-worker.js延时发送消息了,实际使用时,根据实际情况写代码)
//manifest.json 如需使用 tabs API,请在扩展程序manifest中声明 "tabs" 权限。
{
"permissions": [
"tabs"
]
}
// service-worker.js
setTimeout(function () {
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, { greeting: 'Hello from background!' }, function (response) {
console.log(response); // 输出从content.js返回的数据
})
})
}, 5000);
// content.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
if (message.greeting) {
console.log(message.greeting); // 输出: Hello from background!
sendResponse({ response: 'Message received!' });
}
});
2.3 content.js和popup.js
参考2.2章节写代码即可,使用方法一样。
注意事项:
content_scripts向popup主动发消息的前提是popup必须打开!否则需要利用background作中转。- 如果
background和popup同时监听,那么它们都可以同时收到消息,但是只有一个可以sendResponse,一个先发送了,那么另外一个再发送就无效。
2.4 通过 chrome.storage 共享数据
有时候你可能需要在多个部分之间共享数据,chrome.storage 是一个跨脚本的存储机制,可以让背景脚本、弹出页面和内容脚本共享数据。
官方文档👉点击这里
- 存储数据
//manifest.json 如需使用 Storage API,请在扩展程序manifest中声明 "storage" 权限。
{
"permissions": [
"storage"
]
}
// background.js
// service-worker.js存储数据
chrome.storage.local.set({ key1: 'value1' }, function () {
console.log('Data saved!');
});
chrome.storage.local.set({ key2: true, key3: {key4: 'value4'} }, function () {
console.log('Data saved!');
});
- 读取数据
// popup.js
chrome.storage.local.get('key1', function (result) {
console.log('result is ' + JSON.stringify(result));
console.log('Value currently is ' + result.key1);
});
chrome.storage.local.get(['key2'], function (result) {
console.log('result is ' + JSON.stringify(result));
console.log('Value currently is ' + result.key2);
});
chrome.storage.local.get(['key1','key2'], function (result) {
console.log('result is ' + JSON.stringify(result));
console.log('Value currently is ' + result.key2);
});
chrome.storage.local.get({key3: {} }, function (result) {
console.log('result is ' + JSON.stringify(result));
console.log('Value currently is ' + result.key3.key4);
});
chrome.storage.local.get({key5: true , key6:false}, function (result) {
console.log('result is ' + JSON.stringify(result));
console.log('Value currently is ' + result.key5 + ',' + result.key6);
});
- 删除数据
//删除数据
chrome.storage.local.remove(['key1'], function() {
console.log('Key1 removed successfully.');
});
- 清除所有数据
//清除所有数据
chrome.storage.local.clear(function() {
console.log('All data cleared.');
});
- 监听数据变化
//content.js
// 监听存储变化(两种方法都可以)
//chrome.storage.local.onChanged.addListener(function(changes) {
// console.log('Storage area "local" has changed');
// console.log(changes);
//});
chrome.storage.onChanged.addListener(function(changes, area) {
if (area === 'local') {
console.log('Storage area "local" has changed');
console.log(changes);
}
});
setTimeout(function (){
chrome.storage.local.set({ key2: false }, function () {
console.log('Data saved!');
});
},5000)
2.5 使用 chrome.runtime.connect 和长连接
除了使用单次消息发送接收,chrome.runtime.connect 可以创建一个持久的连接,适用于需要长期通信的场景。
popup.js和service-worker.js长连接
// service-worker.js
chrome.runtime.onConnect.addListener(function(port) {
console.log('Connected:', port.name);
port.onMessage.addListener(function(msg) {
if (msg.action === 'getUserInfo') {
// 模拟从后台获取用户信息
const userInfo = { name: 'John Doe', age: 30 };
port.postMessage({ data: userInfo });
}
});
port.onDisconnect.addListener(function() {
console.log('Port disconnected');
});
});
// popup.js
let port = chrome.runtime.connect({ name: 'popup' });
// 请求获取用户信息
port.postMessage({ action: 'getUserInfo' });
// 监听来自service-worker.js的消息
port.onMessage.addListener(function(msg) {
console.log('Received user info:', msg.data);
});
content.js和popup.js长连接
// popup.js
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
let port = chrome.tabs.connect(tabs[0].id, {name: 'test-connect'});
port.postMessage({question: '你是谁啊?'});
port.onMessage.addListener(function(msg) {
alert('收到消息:'+msg.answer);
if(msg.answer && msg.answer.startsWith('我是'))
{
port.postMessage({question: '哦,原来是你啊!'});
}
});
});
// content.js
chrome.runtime.onConnect.addListener(function(port) {
console.log(port);
if(port.name === 'test-connect') {
port.onMessage.addListener(function(msg) {
console.log('收到长连接消息:', msg);
if(msg.question === '你是谁啊?') port.postMessage({answer: '我是容易摔倒的猪!'});
});
}
});
注意事项:
- 连接关闭:连接没有显式关闭时会一直保持,所以要确保在合适的时机断开连接,避免内存泄漏。
- 服务工作线程:在V3版本插件中,背景脚本使用
service worker,它是惰性加载的,意味着它并不是一直在运行,所以要注意如何管理长连接的生命周期。
要实现三方长连接,我们可以使用以下方式:
content.js与service-worker.js通过chrome.runtime.connect建立连接。popup.js也与service-worker.js进行通信。service-worker.js作为中介,协调content.js和popup.js的消息。
前言
前面我们介绍了Chrome插件中存在的4种JS,那么它们之间如何互相通信呢?
1. Chrome插件的5种类型的JS对比
| JS种类 | content script | service worker | popup | devtools |
|---|---|---|---|---|
| 可访问的API | 只能访问dom、i18n、storage、runtime等部分API | 可访问绝大部分API,除了devtools系列 | 可访问绝大部分API,除了devtools系列 | 只能访问 devtools、runtime等部分API |
| DOM访问情况 | 页面DOM | 无 | 弹窗DOM | 页面DOM |
| 生命周期 | 随页面加载/卸载 | 按需唤醒,最长 5 分钟(和V2版本插件有区别) | 随弹窗打开/关闭 | 随 DevTools 打开/关闭 |
| 典型用途 | 修改页面内容、监控用户交互 | 跨标签管理、定时任务、消息路由 | 快速操作入口、状态展示 | 开发者工具集成、调试工具开发 |
2. 消息通信
2.1 popup.js和service-worker.js
弹出页面(popup.js) 和 背景脚本(service-worker.js) 之间的通信通常通过 chrome.runtime.sendMessage 来实现。
popup.js向service-worker.js发送消息
// service-worker.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
if (message.type === 'popupSendMessageToServiceWorker') {
sendResponse({ success: true, message: 'service-worker.js收到消息' });
}
});
// popup.js
chrome.runtime.sendMessage({ type: 'popupSendMessageToServiceWorker' }, function(response) {
console.log(response); // 输出从service-worker.js返回的数据
});
service-worker.js向popup.js发送消息(因为popup.js的生命周期随弹窗打开才开始,所以演示代码里,service-worker.js加了延时发消息)
// popup.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
if (message.type === 'serviceWorkerSendMessageToPopup') {
sendResponse({ success: true, message: 'popup.js收到消息' });
}
});
// service-worker.js
setTimeout(function () {
chrome.runtime.sendMessage({type: 'serviceWorkerSendMessageToPopup'}, function (response) {
console.log(response); // 输出从popup.js返回的数据
})
},
5000
);
2.2 content.js和service-worker.js
content.js 和 service-worker.js 通常通过 chrome.runtime.sendMessage 或 chrome.tabs.sendMessage 进行消息传递。
content.js向service-worker.js发送消息
// service-worker.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
if (message.type === 'contentSendMessageToServiceWorker') {
sendResponse({ success: true, message: 'service-worker.js收到消息' });
}
});
// content.js
chrome.runtime.sendMessage({ type: 'contentSendMessageToServiceWorker' }, function(response) {
console.log(response);
});
service-worker.js向content.js发送消息(演示代码里service-worker.js延时发送消息了,实际使用时,根据实际情况写代码)
//manifest.json 如需使用 tabs API,请在扩展程序manifest中声明 "tabs" 权限。
{
"permissions": [
"tabs"
]
}
// service-worker.js
setTimeout(function () {
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, { greeting: 'Hello from background!' }, function (response) {
console.log(response); // 输出从content.js返回的数据
})
})
}, 5000);
// content.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
if (message.greeting) {
console.log(message.greeting); // 输出: Hello from background!
sendResponse({ response: 'Message received!' });
}
});
2.3 content.js和popup.js
参考2.2章节写代码即可,使用方法一样。
注意事项:
content_scripts向popup主动发消息的前提是popup必须打开!否则需要利用background作中转。- 如果
background和popup同时监听,那么它们都可以同时收到消息,但是只有一个可以sendResponse,一个先发送了,那么另外一个再发送就无效。
2.4 通过 chrome.storage 共享数据
有时候你可能需要在多个部分之间共享数据,chrome.storage 是一个跨脚本的存储机制,可以让背景脚本、弹出页面和内容脚本共享数据。
官方文档👉点击这里
- 存储数据
//manifest.json 如需使用 Storage API,请在扩展程序manifest中声明 "storage" 权限。
{
"permissions": [
"storage"
]
}
// background.js
// service-worker.js存储数据
chrome.storage.local.set({ key1: 'value1' }, function () {
console.log('Data saved!');
});
chrome.storage.local.set({ key2: true, key3: {key4: 'value4'} }, function () {
console.log('Data saved!');
});
- 读取数据
// popup.js
chrome.storage.local.get('key1', function (result) {
console.log('result is ' + JSON.stringify(result));
console.log('Value currently is ' + result.key1);
});
chrome.storage.local.get(['key2'], function (result) {
console.log('result is ' + JSON.stringify(result));
console.log('Value currently is ' + result.key2);
});
chrome.storage.local.get(['key1','key2'], function (result) {
console.log('result is ' + JSON.stringify(result));
console.log('Value currently is ' + result.key2);
});
chrome.storage.local.get({key3: {} }, function (result) {
console.log('result is ' + JSON.stringify(result));
console.log('Value currently is ' + result.key3.key4);
});
chrome.storage.local.get({key5: true , key6:false}, function (result) {
console.log('result is ' + JSON.stringify(result));
console.log('Value currently is ' + result.key5 + ',' + result.key6);
});
- 删除数据
//删除数据
chrome.storage.local.remove(['key1'], function() {
console.log('Key1 removed successfully.');
});
- 清除所有数据
//清除所有数据
chrome.storage.local.clear(function() {
console.log('All data cleared.');
});
- 监听数据变化
//content.js
// 监听存储变化(两种方法都可以)
//chrome.storage.local.onChanged.addListener(function(changes) {
// console.log('Storage area "local" has changed');
// console.log(changes);
//});
chrome.storage.onChanged.addListener(function(changes, area) {
if (area === 'local') {
console.log('Storage area "local" has changed');
console.log(changes);
}
});
setTimeout(function (){
chrome.storage.local.set({ key2: false }, function () {
console.log('Data saved!');
});
},5000)
2.5 使用 chrome.runtime.connect 和长连接
除了使用单次消息发送接收,chrome.runtime.connect 可以创建一个持久的连接,适用于需要长期通信的场景。
popup.js和service-worker.js长连接
// service-worker.js
chrome.runtime.onConnect.addListener(function(port) {
console.log('Connected:', port.name);
port.onMessage.addListener(function(msg) {
if (msg.action === 'getUserInfo') {
// 模拟从后台获取用户信息
const userInfo = { name: 'John Doe', age: 30 };
port.postMessage({ data: userInfo });
}
});
port.onDisconnect.addListener(function() {
console.log('Port disconnected');
});
});
// popup.js
let port = chrome.runtime.connect({ name: 'popup' });
// 请求获取用户信息
port.postMessage({ action: 'getUserInfo' });
// 监听来自service-worker.js的消息
port.onMessage.addListener(function(msg) {
console.log('Received user info:', msg.data);
});
content.js和popup.js长连接
// popup.js
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
let port = chrome.tabs.connect(tabs[0].id, {name: 'test-connect'});
port.postMessage({question: '你是谁啊?'});
port.onMessage.addListener(function(msg) {
alert('收到消息:'+msg.answer);
if(msg.answer && msg.answer.startsWith('我是'))
{
port.postMessage({question: '哦,原来是你啊!'});
}
});
});
// content.js
chrome.runtime.onConnect.addListener(function(port) {
console.log(port);
if(port.name === 'test-connect') {
port.onMessage.addListener(function(msg) {
console.log('收到长连接消息:', msg);
if(msg.question === '你是谁啊?') port.postMessage({answer: '我是容易摔倒的猪!'});
});
}
});
注意事项:
- 连接关闭:连接没有显式关闭时会一直保持,所以要确保在合适的时机断开连接,避免内存泄漏。
- 服务工作线程:在V3版本插件中,背景脚本使用
service worker,它是惰性加载的,意味着它并不是一直在运行,所以要注意如何管理长连接的生命周期。
要实现三方长连接,我们可以使用以下方式:
content.js与service-worker.js通过chrome.runtime.connect建立连接。popup.js也与service-worker.js进行通信。service-worker.js作为中介,协调content.js和popup.js的消息。
版权声明:本文标题:测试开发之路之chrome插件(三)消息通信 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://it.en369.cn/jiaocheng/1754670891a2714182.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。


发表评论