因爲業務需求, 筆者要爲公司開發幾款實用的瀏覽器插件,因此大體花了一天的時間,看完了谷歌瀏覽器插件開發文檔,在這裏特意總結一下經驗, 並經過一個實際案例來複盤插件開發的流程和注意事項.javascript
在開始正文以前,咱們先來看看筆者總結的概覽: css
若是對瀏覽器插件開發比較熟悉的朋友能夠直接看最後一節插件開發實戰。首先咱們看看的瀏覽器插件的定義:html
瀏覽器插件是基於Web技術(例如HTML,JavaScript和CSS)構建的能夠定製瀏覽體驗的小型軟件程序。它們使用戶能夠根據我的須要或偏好來定製Chrome功能和行爲。前端
要想開發一款瀏覽器插件,咱們只須要有一個manifest.json文件便可, 爲了快速上手瀏覽器插件開發,咱們須要把瀏覽器開發者工具打開, 具體步驟以下:vue
經過以上三個步驟咱們就能夠開啓瀏覽器插件開發之旅了.瀏覽器插件通常放在瀏覽器地址欄右側,咱們能夠在manifest.json文件配置插件的icon,並配置必定的規則,就能看到咱們的瀏覽器插件圖標了,以下圖: java
下面咱們來具體講解一下瀏覽器插件開發的核心概念.瀏覽器插件通常涉及如下幾個核心文件:node
筆者畫了一張簡圖來大體表示一下它們之間的關係: jquery
接下來咱們來具體瞭解一下一上幾個核心知識點.webpack
谷歌官網給咱們提供了一份簡單的配置,以下:css3
{
"name": "My Extension",
"version": "2.1",
"description": "Gets information from Google.",
"icons": {
"128": "icon_16.png",
"128": "icon_32.png",
"128": "icon_48.png",
"128": "icon_128.png"
},
"background": {
"persistent": false,
"scripts": ["background_script.js"]
},
"permissions": ["https://*.google.com/", "activeTab"],
"browser_action": {
"default_icon": "icon_16.png",
"default_popup": "popup.html"
}
}
複製代碼
各字段含義介紹以下:
文末會給出完整的配置文件地址,方便你們學習參考.
background頁面主要用來提供一些全局配置, 事件監聽, 業務轉發等.舉幾個經常使用案例:
// background.js
const systems = {
a: '趣談前端',
b: '掘金',
c: '微信'
}
chrome.runtime.onInstalled.addListener(function() {
// 上下文菜單
for (let key of Object.keys(systems)) {
chrome.contextMenus.create({
id: key,
title: systems[key],
type: 'normal',
contexts: ['selection'],
});
}
});
// manifest.json
{
"permissions": ["contextMenus"]
}
複製代碼
效果以下:
chrome.runtime.onInstalled.addListener(function() {
// 相似於何時激活瀏覽器插件圖標這種感受
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([{
conditions: [new chrome.declarativeContent.PageStateMatcher({
pageUrl: {hostSuffix: '.com'},
})
],
actions: [new chrome.declarativeContent.ShowPageAction()]
}]);
});
});
複製代碼
以下圖所示,當頁面地址的後綴不等於.com時,插件icon將不被激活:
3. 和content_script或者popup頁面進行消息通訊chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting == "hello")
sendResponse({farewell: "goodbye"});
});
複製代碼
內容腳本通常植入會被植入到頁面中, 而且能夠控制頁面中的dom. 咱們能夠利用它實現屏蔽網頁廣告, 定製頁面皮膚等操做. 在manifest.json中的基本配置以下:
{
"content_scripts": [{
"matches": [
"http://*/*",
"https://*/*"
],
"js": [
"lib/jquery3.4.min.js",
"content_script.js"
],
"css": ["base.css"]
}],
}
複製代碼
以上代碼中咱們定義了content_scripts容許注入的頁面範圍, 插入頁面的js以及css, 這樣咱們就能輕鬆改變某一個頁面的樣式.好比咱們能夠在頁面中注入一個按鈕:
在後面的瀏覽器插件案例中筆者會詳細介紹content_scripts的用法.popup是用戶點擊插件圖標時打開的一個小窗口,當失去焦點後窗口就當即關閉,咱們通常用它來處理一些簡單的用戶交互和插件說明。
因爲popup窗口也是一個網頁,因此咱們通常會創建一個popup.html和popup.js用來控制popup的頁面展現和交互.咱們在manifest.json中配置以下:
{
"page_action": {
"default_title": "小夕圖片提取插件",
"default_popup": "popup.html"
},
}
複製代碼
這裏要注意一點的是,咱們在popup.html中不能直接使用script腳本,須要用引入腳本文件的方式.以下:
<!DOCTYPE html>
<html> <head> <title>在線圖片提取工具</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <div class="pop-wrap"> </div> <script src="lib/jquery3.4.min.js"></script> <script src="popup.js"></script> </body> </html> 複製代碼
如下是筆者寫的一個插件的popup頁面:
對於一個相對複雜的瀏覽器插件來講,咱們不只僅只操做dom或者提供基本的功能就好了,咱們還須要向第三方或者本身的服務器抓取有用的頁面數據,這個時候就須要用到插件的通訊機制了.
由於content_script腳本存在於當前頁面,受同源策略影響,致使咱們沒法將捕獲到的數據傳給第三方平臺或者本身的服務器, 因此咱們須要基於瀏覽器的通訊API.一下是谷歌瀏覽器插件的通訊流程:
由官方文檔可知popup能夠直接訪問background頁的方法,因此popup能夠直接與其通訊:
// background.js
var getData = (data) => { console.log('拿到數據:' + data) }
// popup.js
let bgObj = chrome.extension.getBackgroundPage();
bgObj.getData(); // 訪問bg的函數
複製代碼
這裏咱們使用chrome的tabs API,以下:
// popup.js
// 發送消息給content_script
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, "activeBtn", function(response) {
console.log(response);
});
});
// 接收消息
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting == "hello")
sendResponse({farewell: "goodbye"});
});
複製代碼
content_script接收和發送消息:
// 接收消息
chrome.runtime.onMessage.addListener(
function(message, sender, sendResponse) {
if (message == "activeBtn"){
// ...
sendResponse({farewell: "激活成功"});
}
});
// 主動發送消息
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
console.log(response, document.body);
// document.body.style.backgroundColor="orange"
});
複製代碼
有關消息的長鏈接,在谷歌官網也寫的很清楚:
咱們能夠採用以下方式進行長鏈接:// content_script.js
var port = chrome.runtime.connect({name: "徐小夕"});
port.postMessage({Ling: "你好"});
port.onMessage.addListener(function(msg) {
if (msg.question == "你是作什麼滴?")
port.postMessage({answer: "搬磚"});
else if (msg.question == "搬磚有錢嗎?")
port.postMessage({answer: "木有"});
});
// popup.js
chrome.runtime.onConnect.addListener(function(port) {
port.onMessage.addListener(function(msg) {
if (msg.Ling == "你好")
port.postMessage({question: "你是作什麼滴?"});
else if (msg.answer == "搬磚")
port.postMessage({question: "搬磚有錢嗎?"});
else if (msg.answer == "木有")
port.postMessage({question: "太難了."});
});
});
複製代碼
chrome.storage用來針對插件全局進行數據存儲,咱們在任何一個頁面(popup或content_script或background)下存儲了數據,咱們在以上三個頁面均可以獲取到, 具體用法以下:
獲取數據
chrome.storage.sync.get('imgArr', function(data) {
console.log(data)
});
// 保存數據
chrome.storage.sync.set({'imgArr': imgArr}, function() {
console.log('保存成功');
});
// 另外一種方式
chrome.storage.local.set({key: value}, function() {
console.log('Value is set to ' + value);
});
複製代碼
谷歌瀏覽器的插件應用場景不少,正如文章開頭的思惟導圖中寫的.如下是筆者總結的一些應用場景,你們感興趣能夠嘗試去實現:
還有不少實用工具能夠開發,你們能夠好好把玩。接下來就來經過實現一個網頁圖片提取插件,來總結如下瀏覽器插件開發流程。
首先仍是按照筆者的風格,在開發任何一種工具以前都要明確需求,因此咱們來看看該插件的功能點:
基本上就這幾個功能,接下來我會展現核心代碼,在介紹代碼以前咱們先預覽一下插件的實現效果:
插件目錄結構以下: 由於插件的開發比較簡單,因此我直接用jquery開發。這裏咱們主要關注popup.js和content_script.js, popup.js中主要用來獲取從content_script頁傳過來的圖片數據,並展現在popup.html中,另外又一個須要注意的是當頁面沒有注入生成按鈕時,popupu須要發送信息給content頁面,主動讓其生成按鈕,代碼以下:chrome.storage.sync.get('imgArr', function(data) {
data.imgArr && data.imgArr.forEach(item => {
var imgWrap = $("<div class='img-box'></div>")
var img = $("<img src='" + item + "' alt='" + item + "' />")
imgWrap.append(img);
$('#content').append(imgWrap);
$('.empty').hide();
})
});
$('#activeBtn').click(function(element) {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, "activeBtn", function(response) {
console.log(response);
});
});
});
複製代碼
對於content頁面,咱們須要實現的是動態生成按鈕,而且在頁面中植入彈窗來展現獲取到的圖片,另外一方面須要將圖片數據傳遞給storage,以便popup頁面能夠獲取圖片數據。
因爲頁面比較簡單,筆者就不用過多的第三方庫了,筆者先簡單手寫一個modal組件,代碼以下:
// 彈窗
~function Modal() {
var modal;
if(this instanceof Modal) {
this.init = function(opt) {
modal = $("<div class='modal'></div>");
var title = $("<div class='modal-title'>" + opt.title + "</div>");
var close_btn = $("<span class='modal-close-btn'>X</span>");
var content = $("<div class='modal-content'></div>");
var mask = $("<div class='modal-mask'></div>");
close_btn.click(function(){
modal.hide()
})
title.append(close_btn);
content.append(title);
content.append(opt.content);
modal.append(content);
modal.append(mask);
$('body').append(modal);
}
this.show = function(opt) {
if(modal) {
modal.show();
}else {
var options = {
title: opt.title || '標題',
content: opt.content || ''
}
this.init(options)
modal.show();
}
}
this.hide = function() {
modal.hide();
}
}else {
window.Modal = new Modal()
}
}()
複製代碼
第一步,咱們先批量獲取頁面圖片數據:
var imgArr = []
$('img').each(function(i) {
var src = $(this).attr('src');
var realSrc = /^(http|https)/.test(src) ? src : location.protocol+ '//' + location.host + src;
imgArr.push(realSrc)
})
複製代碼
由於圖片的src路徑多是相對地址,因此筆者在這裏用正則簡單處理如下,固然咱們能夠進行更細粒度的控制。
第二步,將圖片數據存儲到storage中:
chrome.storage.sync.set({'imgArr': imgArr}, function() {
console.log('保存成功');
});
複製代碼
第三步,生成預覽圖片的彈窗,這裏用筆者上面實現的modal組件:
Modal.show({
title: '提取結果',
content: imgBox
})
複製代碼
第四步,當popup發送激活按鈕的通知時,咱們要在網頁中動態插入生成按鈕:
chrome.runtime.onMessage.addListener(
function(message, sender, sendResponse) {
if (message == "activeBtn"){
if(!$('.crawl-btn')) {
$('body').append("<div class='crawl-btn'>提取</div>")
}else {
$('.crawl-btn').css("background-color","orange");
setTimeout(() => {
$('.crawl-btn').css("background-color","#06c");
}, 3000);
}
sendResponse({farewell: "激活成功"});
}
});
複製代碼
setTimeout那段純屬是爲了吸引用戶視線,固然咱們能夠用更優雅的方式來處理。 插件核心代碼主要是這些,固然還有不少細節要考慮,我把配置文件和一些細節放到github了,若是感興趣的朋友能夠安裝感覺一下。
github地址:一款提取網頁圖片數據的瀏覽器插件
若是想學習更多H5遊戲, webpack,node,gulp,css3,javascript,nodeJS,canvas數據可視化等前端知識和實戰,歡迎在公號《趣談前端》加入咱們的技術羣一塊兒學習討論,共同探索前端的邊界。