[入門系列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
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。