[入门系列3 - background、content、popup的通信 - 掘金](https://juejin.cn/post/6844903985711677453 )]
前言
😋😋😋嘿,各位爷好~~
前面两节简单的总结了一些关于什么是浏览器插件,以及浏览得的manifest.json
文件配置。同时在后续也给插件增加了页面和逻辑,说明了background
、popup
、content
三个字段的具体使用。
不同字段对应着不同的作用,协作构成了插件的强大功能。合作就得沟通,就像Electron
的主进程和渲染进程通信,那它们之间是如何通信的呢?
插件的架构体系
插件呢,必须具有存在位于浏览器工具栏中的图标,工具栏图标允许轻松访问,并使用户了解安装了哪些插件。大多数用户通过单击图标,使用其弹出窗口进行交互,比如CORS跨域插件,谷歌翻译插件等等。
插件的体系结构是取决于其功能,但大多数功能强大的插件包括以下多个组件:
manifest
background scripts
ui elements ==> popup
content scripts
optional page
备注:就像插件允许用户自定义Chrome浏览器一样,optional page
可以自定义插件。在chrome40以前,使用options_page配置
;在chrome40以后,则使用options_ui
配置。
组件的background
、popup
、content
三个字段整体关系图如下:

通信
插件的不同组件之间通常需要彼此通信,不同的HTML页面可以使用chrome.extension
方法找到彼此,例如getViews()和getBackgroundPage()。一旦页面引用了其他扩展页面,第一个页面就可以调用其他页面上的函数并操纵它们的DOM。此外,插件的所有组件还可以使用storage API存储值,并使用消息传递进行通信。
而对于组件background
、popup
、content
,具体通信可以看下图:

可以看到存在6种通信路径:
popup
和background
之间的通信background
给popup
发送消息popup
给background
发送消息
background
和content
之间的通信background
给content
发送消息content
给background
发送消息
popup
和content
之间的通信popup
给content
发送消息content
给popup
发送消息
脚本权限
我们已经了解了存在的几种通信路径,通信意味着各种API的相互调用,因此在实践之前,也需要去了解一点关于chrome 插件的脚本权限
脚本的类型决定着脚本存在什么权限:比如Chrome API
、DOM 访问
、跨域访问
、原页面JS访问
,具体如图:

=====> 图使用markdown编辑 好了,了解了权限以后,就知道什么脚本可以使用何种API来实现信息传递,接下来就尝试去打通每一关吧。
popup
和background
之间的通信
首先,给一个大致通信图。关于content script
、popup script
、background script
,它们之间的通信总体概览图如下:

开始吧。还是和以前一样,新建插件文件夹,增加必须的manifest.json
和基本文件。
background
给popup
发送消息
插件的background
,对于浏览器只存在一个,而对于popup
,不同的 tab 就会存在一个前端,如果background
需要给不同前端发送信息,就需要特殊的tab id。这里是针对background
给popup
传递信息。
background.js
添加代码:
function toPopup() {
alert('to popup!')
}
复制代码
popup.js
添加代码:
const bg = chrome.extension.getBackgroundPage()
document.getElementById('rBgInfo').onclick = function() {
bg.toPopup()
}
复制代码
在popup.html
引入popup.js
,并添加id为rBgInfo
的按钮,安装插件,点击按钮,如果弹窗如下样式,则表明成功。

popup
给background
发送消息
background => popup
是通过getBackgroundPage
,而popup => background
是通过getViews
。
下面就来瞧一下
使用长连接
在popup.js
增加如下代码:
// 使用长连接
let port = chrome.extension.connect({
name: 'popup-name'
})
// 使用postMs 发送信息
port.postMessage('给 background 传递信息~')
// 接收信息
port.onMessage.addListener(msg => {
console.log('接收的信息:', msg)
})
复制代码
在background.js
增加如下代码:
// 获取所有 tab
const pups = chrome.extension.getViews({
type: 'popup'
}) || []
// 输出第一个使用插件页面的url
if (pups.length) {
console.log(pups[0].location.href)
}
复制代码
点击插件刷新按钮,点击【背景页】按钮,可以看到每次点击一下插件图标,就会发送一次信息。

这也告诉了 chrome 插件的另一个机制:点击图标出现和隐藏popup
弹窗页面,实际上是对整个页面的销毁,类似于关闭网页,而不是切换网页。(很重要的哦)
操作 DOM
除了信息传递,background
可能也需要对popup.html
的页面进行操作,比如检测到当前是万圣节🎃,给插件页面添加个happy halloween
。
首先给popup.html
增加一个text
<p id="pbText">不是万圣节</p>
复制代码
然后只需要在background.js
中如下处理:
// 使用长连接 - 监听 popup 传递来的消息
chrome.extension.onConnect.addListener(port => {
console.log('连接中------------')
port.onMessage.addListener(msg => {
console.log('接收消息:', msg)
getAll()
port.postMessage('popup,我收到了你的信息~')
})
})
// 获取所有 tab
function getAll() {
const views = chrome.extension.getViews({
type: 'popup'
})
for (let o of views) {
console.log(111)
o.document.getElementById('pbText').innerHTML = "万圣节🎃快乐"
}
}
复制代码
添加getAll()
函数,将函数防止长连接即可。这里主要想展示chrome.extension.getViews
函数的使用。
刷新插件,点击插件图标,就会弹窗如下页面了:

popup
和content
之间的通信
有了background
和popup
,下面需要做的就是创建一个content
页面。
manifest
添加下列配置
{
...
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"content.js"
]
}
]
}
复制代码
content
给popup
发送消息
首先在content.js
添加如下代码:
// Chrome提供的大部分API是不支持在content_scripts中运行
// sendMessage onMessage 是可以使用
chrome.runtime.sendMessage({
info: "我是 content.js"
}, res => {
// 答复
alert(res)
})
复制代码
代码负责发送信息和接收反馈,然后给popup.js
添加:
chrome.runtime.onMessage.addListener((req,sender, sendResponse) => {
sendResponse('我收到了你的来信')
console.log('接收了来自 content.js的消息', req.info)
})
复制代码
代码负责接收消息和发送反馈。
刷新插件,点击插件按钮,打开一个页面,保持插件popup
处于活跃状态(上面讲了哈~,插件关闭等于页面销毁),然后刷新页面,会发现浏览器弹出弹窗:

最后,右键插件图标,点击“审查弹窗内容”,可以看到content.js
和popup.js
的console.log
日志(👻这等于告诉您如何调试插件~)

弹窗说明我们的程序是成功运行的,日志打印表明我们的通信是成功的,现在我们已经知道了content
给popup
发送消息。
popup
给content
发送消息
其实上面已经告诉了popup
给content
发送信息了,但毕竟不是popup
主动地,谈恋爱了,肯定需要主动一些了。
给popup
添加如下代码,放入rBgInfo按钮点击事件:
// popup ---> content
chrome.tabs.query({
active: true,
currentWindow: true
}, (tabs) => {
let message = {
info: '来自popup的情书💌'
}
chrome.tabs.sendMessage(tabs[0].id, message, res => {
console.log('popup=>content')
console.log(res)
})
})
复制代码
寄送一封信,content
得接收信:
// get popup2content info
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log(request.info)
sendResponse('我收到了你的情书,popup~')
})
复制代码
点击插件刷新按钮,打开页面,点击弹窗的rBgInfo按钮,日志打印如下:

关于popup
给content
的通信又又又成功了~
background
和content
之间的通信
background
和content
之间的通信与popup
和content
类似的,写者就不写demo了,与上面一样。
长连接与短连接
在上面的一些demo中,可以看到通信使用了两个函数,一个就是sendMessage
,另一个就是connect
,其实这两个分别对应着不同的连接方式:
- 长连接:
chrome.tabs.connect
和chrome.runtime.connect
- 短连接:
chrome.tabs.sendMessage
总结
了解了脚本之前的通信以后,才算真正的入门了,希望各位能学到点什么。下面关于chrome 插件的博客,可能会涉及到具体真正插件开发的实践了,更新或许会慢一点,见谅❤❤❤!
备注:这几天工作较忙,写博客都得挤时间了。希望大家也能在工作之余过好每天,谢谢时光~
作者:Rabbitzzc
链接:https://juejin.cn/post/6844903985711677453
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。