Chrome 插件是什么
其實(shí),這東西應(yīng)該叫Chrome擴(kuò)展(Chrome Extension),Chrome插件這種叫法是大眾的習(xí)慣稱(chēng)呼。
Chrome 插件 目錄結(jié)構(gòu)
├── manifest.json
├── html
│ └── index.html
├── images
│ ├── icon-128.png
│ └── icon-16.png
├── scripts
│ └── background.js
├── styles
│ └── main.css
└─_locales
├── en
│ └── messages.json
│
└── zh_CN
└── messages.json
上圖可以看出,Chrome 插件 其實(shí)就是一個(gè)由HTML、CSS、JS、圖片等資源組成的一個(gè)應(yīng)用,本質(zhì)上來(lái)說(shuō)就是webapp。
Chrome 插件 能幫我們做什么?
- 網(wǎng)絡(luò)請(qǐng)求攔截處理
- 書(shū)簽控制
- 窗口控制
- 通信機(jī)制
- 右鍵菜單控制
- 搜索欄快捷操作
- ...
文件介紹
manifest.json
{
// 清單文件的版本,這個(gè)必須寫(xiě),而且必須是2
"manifest_version": 2,
// 插件的名稱(chēng)
"name": "demo",
// 插件的版本
"version": "1.0.0",
// 插件描述
"description": "簡(jiǎn)單的Chrome擴(kuò)展demo",
// 圖標(biāo),一般偷懶全部用一個(gè)尺寸的也沒(méi)問(wèn)題
"icons":
{
"16": "img/icon.png",
"48": "img/icon.png",
"128": "img/icon.png"
},
// 會(huì)一直常駐的后臺(tái)JS或后臺(tái)頁(yè)面
"background":
{
// 2種指定方式,如果指定JS,那么會(huì)自動(dòng)生成一個(gè)背景頁(yè)
"page": "background.html"
//"scripts": ["js/background.js"]
},
// 瀏覽器右上角圖標(biāo)設(shè)置,browser_action、page_action、app必須三選一
"browser_action":
{
"default_icon": "img/icon.png",
// 圖標(biāo)懸停時(shí)的標(biāo)題,可選
"default_title": "這是一個(gè)示例Chrome插件",
"default_popup": "popup.html"
},
// 需要直接注入頁(yè)面的JS
"content_scripts":
[
{
//"matches": ["http://*/*", "https://*/*"],
// "<all_urls>" 表示匹配所有地址
"matches": ["<all_urls>"],
// 多個(gè)JS按順序注入
"js": ["js/jquery-1.8.3.js", "js/content-script.js"],
// JS的注入可以隨便一點(diǎn),但是CSS的注意就要千萬(wàn)小心了,因?yàn)橐徊恍⌒木涂赡苡绊懭謽邮? "css": ["css/custom.css"],
// 代碼注入的時(shí)間,可選值: "document_start", "document_end", or "document_idle",最后一個(gè)表示頁(yè)面空閑時(shí),默認(rèn)document_idle
"run_at": "document_start"
},
],
// 權(quán)限申請(qǐng)
"permissions":
[
"contextMenus", // 右鍵菜單
"tabs", // 標(biāo)簽
"notifications", // 通知
"webRequest", // web請(qǐng)求
"webRequestBlocking",
"storage", // 插件本地存儲(chǔ)
"http://*/*", // 可以通過(guò)executeScript或者insertCSS訪問(wèn)的網(wǎng)站
"https://*/*" // 可以通過(guò)executeScript或者insertCSS訪問(wèn)的網(wǎng)站
],
// 普通頁(yè)面能夠直接訪問(wèn)的插件資源列表,如果不設(shè)置是無(wú)法直接訪問(wèn)的
"web_accessible_resources": ["js/inject.js"],
// 該擴(kuò)展的主頁(yè)地址
"homepage_url": "https://www.baidu.com",
// 覆蓋瀏覽器默認(rèn)頁(yè)面
"chrome_url_overrides":
{
// 覆蓋瀏覽器默認(rèn)的新標(biāo)簽頁(yè)
"newtab": "newtab.html"
},
// Chrome40以前的插件配置頁(yè)寫(xiě)法
"options_page": "options.html",
// Chrome40以后的插件配置頁(yè)寫(xiě)法,如果2個(gè)都寫(xiě),新版Chrome只認(rèn)后面這一個(gè)
"options_ui":
{
"page": "options.html",
// 添加一些默認(rèn)的樣式,推薦使用
"chrome_style": true
},
// 向地址欄注冊(cè)一個(gè)關(guān)鍵字以提供搜索建議,只能設(shè)置一個(gè)關(guān)鍵字
"omnibox": { "keyword" : "go" },
// 默認(rèn)語(yǔ)言
"default_locale": "zh_CN",
// devtools頁(yè)面入口,注意只能指向一個(gè)HTML文件,不能是JS文件
"devtools_page": "devtools.html"
}
content-scripts
Content scripts是在Web頁(yè)面內(nèi)運(yùn)行的javascript腳本。通過(guò)使用標(biāo)準(zhǔn)的DOM,它們可以獲取瀏覽器所訪問(wèn)頁(yè)面的詳細(xì)信息,并可以修改這些信息。我們可以使用它來(lái)進(jìn)行廣告屏蔽、頁(yè)面圖片提取視頻提取等。
配置如下:
{
// 需要直接注入頁(yè)面的JS
"content_scripts":
[
{
//"matches": ["http://*/*", "https://*/*"],
// "<all_urls>" 表示匹配所有地址
"matches": ["<all_urls>"],
// 多個(gè)JS按順序注入
"js": ["js/jquery-1.8.3.js", "js/content-script.js"],
// JS的注入可以隨便一點(diǎn),但是CSS的注意就要千萬(wàn)小心了,因?yàn)橐徊恍⌒木涂赡苡绊懭謽邮? "css": ["css/custom.css"],
// 代碼注入的時(shí)間,可選值: "document_start", "document_end", or "document_idle",最后一個(gè)表示頁(yè)面空閑時(shí),默認(rèn)document_idle
"run_at": "document_start"
}
],
}
content-scripts和原始頁(yè)面共享DOM,但是不共享JS,如要訪問(wèn)頁(yè)面JS(例如某個(gè)JS變量),只能通過(guò)injected js來(lái)實(shí)現(xiàn)。
不能使用除了chrome.extension之外的chrome.* 的接口。
不過(guò)Content scripts 可以使用messages機(jī)制與它所在的擴(kuò)展通信,來(lái)間接使用chrome.*接口,或訪問(wèn)擴(kuò)展數(shù)據(jù)。Content scripts還可以通過(guò)共享的DOM來(lái)與web頁(yè)面通信。
background
background后臺(tái)頁(yè)面,在瀏覽器前臺(tái)看不到的頁(yè)面,可以以后臺(tái)進(jìn)程的方式進(jìn)行運(yùn)行,也可以以事件的方式運(yùn)行。需要打開(kāi)擴(kuò)展程序的開(kāi)發(fā)者模式才能看到。
打開(kāi)方式如下:

配置如下:
{
// 會(huì)一直常駐的后臺(tái)JS或后臺(tái)頁(yè)面
"background":
{
// 2種指定方式,如果指定JS,那么會(huì)自動(dòng)生成一個(gè)背景頁(yè)
"page": "background.html"
//"scripts": ["js/background.js"]
},
}
所有頁(yè)面共用同一個(gè)background,它與外部通過(guò)消息傳遞。 它的權(quán)限非常高,可以無(wú)限制跨域,也可以通過(guò)chrome.storage持久化去保存一些用戶配置。
popup
popup是點(diǎn)擊browser_action或者page_action圖標(biāo)時(shí)打開(kāi)的一個(gè)小窗口網(wǎng)頁(yè),焦點(diǎn)離開(kāi)網(wǎng)頁(yè)就立即關(guān)閉,一般用來(lái)做一些臨時(shí)性的交互。popup的控制臺(tái)是直接右鍵popup,選擇檢查即可。

popup可以寫(xiě)你想要的HTML內(nèi)容,不過(guò)它的生命周期很短,單擊圖標(biāo)打開(kāi)popup,焦點(diǎn)離開(kāi)又立即關(guān)閉。
在權(quán)限上,它和background非常類(lèi)似,它們之間最大的不同是生命周期的不同,popup中可以直接通過(guò)chrome.extension.getBackgroundPage()獲取background的window對(duì)象。
功能展示
右鍵菜單
Chrome插件可以對(duì)普通頁(yè)面、選中的文字、圖片、鏈接等元素,在右鍵的時(shí)候,是通過(guò)chrome.contextMenusAPI實(shí)現(xiàn)一些快捷功能。
右鍵菜單示例
// manifest.json
{"permissions": ["contextMenus"]}
// background.js
chrome.contextMenus.create({
title: "右鍵菜單",
onclick: function(){alert('您點(diǎn)擊了右鍵菜單!');}
});
效果:

chrome_url_overrides
配置chrome_url_overrides可以替換Chrome特定頁(yè)面。
配置如下:
"chrome_url_overrides": {
"newtab": "newtab.html", // 替換鑫打開(kāi)標(biāo)簽 chrome://newtab
"history": "history.html", // 替換歷史記錄 chrome://history
"bookmarks": "bookmarks.html" // 替換瀏覽器書(shū)簽 chrome://bookmarks
}
注意:
- 一個(gè)擴(kuò)展只能替代一個(gè)特定頁(yè)面;
- 不能替代隱身窗口的新標(biāo)簽頁(yè);
- 網(wǎng)頁(yè)必須設(shè)置title,以便隱藏網(wǎng)頁(yè)的URL。
popup動(dòng)態(tài)注入或執(zhí)行JS
background和popup中無(wú)法直接訪問(wèn)頁(yè)面DOM,但是可以通過(guò)chrome.tabs.executeScript來(lái)執(zhí)行腳本,從而實(shí)現(xiàn)訪問(wèn)web頁(yè)面的DOM。
manifest.json配置:
{
"permissions": [
"tabs", "http://*/*", "https://*/*"
],
}
localStorage中插值
// 獲取當(dāng)前選項(xiàng)卡ID
function getCurrentTabId(callback) {
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
if (callback) callback(tabs.length ? tabs[0].id : null);
});
}
function executeScriptToCurrentTab(code) {
getCurrentTabId((tabId) => {
chrome.tabs.executeScript(tabId, { code });
});
}
executeScriptToCurrentTab(`localStorage.setItem('overviewGuideShow', false)`);
消息通信
概覽
| content-script | popup-js | background-js | |
|---|---|---|---|
| content-script | - | chrome.runtime.sendMessage chrome.runtime.connect |
chrome.runtime.sendMessage chrome.runtime.connect |
| popup-js | chrome.tabs.sendMessage chrome.tabs.connect |
- | chrome.extension.getBackgroundPage() |
| background-js | chrome.tabs.sendMessage chrome.tabs.connect |
chrome.extension.getViews | - |
popup和background
popup可以直接調(diào)用background中的JS方法,也可以直接訪問(wèn)background的DOM:
// background.js
function test() {
alert('我是background!');
}
// popup.js
var background = chrome.extension.getBackgroundPage();
background.test();
alert(bg.document.body.innerHTML); // 獲取background的DOM
popup、background向content主動(dòng)發(fā)消息
background.js或者popup.js:
function sendMessageToContentScript(message, callback) {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, message, function(response) {
if(callback) callback(response);
});
});
}
sendMessageToContentScript({text: '我是popup'}, function(response) {
console.log('來(lái)自content的回復(fù):'+response);
});
content-script.js:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log(request);
sendResponse('收到消息popup或background的消息');
});
content-script主動(dòng)發(fā)消息給后臺(tái)
content-script.js:
chrome.runtime.sendMessage({greeting: '我是content-script,這是我發(fā)送的消息!'}, (response) => {
console.log('這是后臺(tái)返回的消息:' + response);
});
background.js 或者 popup.js:
// 監(jiān)聽(tīng)來(lái)自content-script的消息
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log(request, sender, sendResponse);
sendResponse('我是后臺(tái),我已收到你的消息:' + JSON.stringify(request));
});
注意:
popup每次打開(kāi)都會(huì)走一次創(chuàng)建渲染流程,所以在popup未打開(kāi)的情況下是接收不到content_script發(fā)送的消息,只能通過(guò)background進(jìn)行間接發(fā)送。
調(diào)試
打開(kāi)擴(kuò)展程序,勾選開(kāi)發(fā)者模式,選擇加載已解壓的擴(kuò)展程序。
同時(shí)在代碼變動(dòng)后都需要去刷新一下插件。

也可以用腳手架去開(kāi)發(fā)Chrome插件,相對(duì)會(huì)更方便一些,腳手架可以幫我們熱重載插件。
這里是一個(gè)Chrome 腳手架,使用 Vue.js + webpack 來(lái)開(kāi)發(fā)和打包Chrome擴(kuò)展, 支持熱重載
https://github.com/jae-jae/chrome-extension-gulu