基本介紹
開發瀏覽器插件,首先需要先了解他的結構,瀏覽器擴展通常包括以下幾個部分
├── manifest.json
├── package.json
├── vite.config.js
├── src
├── background
│ └── index.js
├── content
│ └── content.js
├── icons
│ └── icon_16x16.png
│ └── icon_48x48.png
│ └── icon_128x128.png
├── popup
├── App.vue
├── index.html
├── main.ts
└── style.css
manifest.json
:擴展的配置文件,是插件的入口文件
background.js
或 background
目錄:包含擴展的后臺腳本,它在插件安裝時就會加載,并且在瀏覽器運行期間始終保持活動狀態
content
:在網頁中注入的腳本
popup
:用戶界面部分,是插件彈框頁面
icons
是放置插件的 16、48、128 的 png 圖片
manifest.json
配置
{"manifest_version": 2,"name": "My Browser Extension","version": "1.0","background": {"scripts": ["background/index.js"]},"permissions": ["activeTab","storage"],"icons": {"16": "icon.png","48": "icon.png","128": "icon.png"},"content_scripts": [{"matches": ["<all_urls>"],"js": ["content/content.js"]}]
}
配置說明:
manifest_version:指定了manifest.json文件的版本號為2,表示遵循Manifest V2規范。
name:指定插件的名稱。
version:指定插件的版本號為"1.0.0"。
description:描述插件的簡要描述,這里是空字符串,可以填寫插件的功能介紹等信息。
author:指定插件的作者。
icons:包含不同尺寸的圖標文件路徑,用于在瀏覽器中顯示插件圖標。
options_page:指定插件的選項頁面為"options.html"。
page_action:配置頁面操作相關的信息,包括默認圖標、標題和彈出頁面。
content_security_policy:設置內容安全策略,限制了腳本和對象的來源,以增強安全性。
background:配置后臺頁面的持久性和后臺腳本文件路徑。
content_scripts:定義內容腳本,指定了腳本文件路徑、匹配的URL以及運行時機。
permissions:列出插件需要的權限,包括處理聲明式內容、標簽、活動標簽、Cookie、網絡請求、存儲等。
web_accessible_resources:指定可以從插件外部訪問的資源,這里是"fonts/*",表示可以訪問fonts文件夾下的所有資源。
創建項目
npm install -g @vue/cli
vue create my-browser-extension
cd my-browser-extension
消息通信
5種類型的JS對比
一、popup.js
和service-worker.js
彈出頁面(popup.js
) 和 背景腳本(service-worker.js
) 之間的通信可以通過chrome.runtime.sendMessage
來實現
1.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返回的數據
});
2.service-worker.js
向 popup.js
發送消息
背景腳本(service-worker.js
)向彈出頁面(popup.js
) 發送消息
// popup.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {if (message.type === 'serviceWorkerSendMessageToPopup') {sendResponse({ success: true, message: 'popup.js收到消息' });}
});// service-worker.js
chrome.runtime.sendMessage({type: 'serviceWorkerSendMessageToPopup'}, function (response) {console.log(response); // 輸出從popup.js返回的數據
})
二、content.js
和service-worker.js
content.js
和 service-worker.js
通常通過 chrome.runtime.sendMessage
或 chrome.tabs.sendMessage
進行消息傳遞。
1.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);
});
2.service-worker.js
向 content.js
發送消息
//manifest.json 如需使用 tabs API,請在擴展程序manifest中聲明 "tabs" 權限。
{"permissions": ["tabs"]
}// service-worker.js
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返回的數據})
})// content.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {if (message.greeting) {console.log(message.greeting); // 輸出: Hello from background!sendResponse({ response: 'Message received!' });}
});
三、content.js
和popup.js
content_scripts
向 popup
主動發消息的前提是 popup
必須打開!否則需要利用 background
作中轉。
如果 background
和 popup
同時監聽,那么它們都可以同時收到消息,但是只有一個可以 sendResponse
,一個先發送了,那么另外一個再發送就無效
使用和二的一樣
// content.js
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {chrome.tabs.sendMessage(tabs[0].id, { greeting: 'Hello from background!' }, function (response) {console.log(response); // 輸出從popup.js返回的數據})
})// popup.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {if (message.greeting) {console.log(message.greeting); // 輸出: Hello from background!sendResponse({ response: 'Message received!' });}
});
四、通過 chrome.storage
共享數據
有時候可能需要在多個部分之間共享數據,chrome.storage
是一個跨腳本的存儲機制,可以讓背景腳本、彈出頁面和內容腳本共享數據。這個類似于網頁中的local 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)
五、使用 chrome.runtime.connect
和長連接
除了單次消息發送接收,chrome.runtime.connect
可以創建一個持久的連接,適用于需要長期通信的場景。
1.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);
});
2.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: '我是容易摔倒的豬!'});});}
});
實現三方長連接方式:
content.js
與 service-worker.js
通過 chrome.runtime.connect
建立連接。
popup.js
也與 service-worker.js
進行通信。
service-worker.js
作為中介,協調 content.js
和 popup.js
的消息。
六、插件使用限制
1、content.js
的腳本限制,在manifest.json
中的content_scripts
設置matches
中執行的域名。
"content_scripts": [{"js": ["js/content.js"],"matches": ["http://wangpu.taobao.com/*", "https://wangpu.taobao.com/*", "http://myseller.taobao.com/*", "https://myseller.taobao.com/*"],"run_at": "document_idle"}]
2、插件的popup
頁面是否顯示
在background.js
中通過 window.chrome.declarativeContent.onPageChanged.addRules
添加域名限制。
window.chrome.runtime.onInstalled.addListener(function () {window.chrome.declarativeContent.onPageChanged.removeRules(undefined, function () {window.chrome.declarativeContent.onPageChanged.addRules([{conditions: [new window.chrome.declarativeContent.PageStateMatcher({pageUrl: { urlContains: 'wangpu.taobao.com' }})],actions: [new window.chrome.declarativeContent.ShowPageAction()]}])})
})
window.chrome.declarativeContent是Chrome瀏覽器擴展程序中用于定義內容腳本的API。其中,urlContains、urlMatches和urlPrefix是用于匹配網頁URL的條件。
- urlContains:表示URL包含指定的字符串時條件匹配。例如,如果指定urlContains: ‘example’,則只有當網頁URL中包含"example"時條件才會匹配。
- urlMatches:表示URL匹配指定的正則表達式時條件匹配。例如,如果指定urlMatches: > ‘https://www.example.com/*’,則只有當網頁URL以"https://www.example.com/"開頭時條件才會匹配。
- urlPrefix:表示URL以指定的字符串開頭時條件匹配。例如,如果指定urlPrefix: ‘https://example.com’,則只有當網頁URL以"https://example.com"開頭時條件才會匹配。