新聞中心
前言
基于谷歌瀏覽器的插件層出不窮, 它可以幫助我們解決單一網(wǎng)站解決不了的很多問題,也有很多前端極客們開發(fā)了大量有意思的瀏覽器插件,所以我也花了大概一天的時(shí)間,看完了谷歌瀏覽器插件開發(fā)文檔,在這里特地總結(jié)一下經(jīng)驗(yàn), 并通過一個(gè)實(shí)際案例來復(fù)盤插件開發(fā)的流程和注意事項(xiàng)。

創(chuàng)新互聯(lián)公司成都網(wǎng)站建設(shè)按需設(shè)計(jì),是成都網(wǎng)站營銷公司,為成都廣告設(shè)計(jì)提供網(wǎng)站建設(shè)服務(wù),有成熟的網(wǎng)站定制合作流程,提供網(wǎng)站定制設(shè)計(jì)服務(wù):原型圖制作、網(wǎng)站創(chuàng)意設(shè)計(jì)、前端HTML5制作、后臺(tái)程序開發(fā)等。成都網(wǎng)站設(shè)計(jì)熱線:13518219792
你將收獲
- 如何快速上手瀏覽器插件開發(fā)。
- 瀏覽器插件開發(fā)的核心概念。
- 瀏覽器插件的通信機(jī)制。
- 瀏覽器插件的數(shù)據(jù)存儲(chǔ)。
- 瀏覽器插件的應(yīng)用場景。
- 開發(fā)一款抓取網(wǎng)站圖片資源的瀏覽器插件。
正文
在開始正文之前,我們先來看看筆者總結(jié)的概覽:
如果對(duì)瀏覽器插件開發(fā)比較熟悉的朋友可以直接看最后一節(jié)插件開發(fā)實(shí)戰(zhàn)。
1、入門
首先我們看看的瀏覽器插件的定義:
瀏覽器插件是基于Web技術(shù)(例如HTML,JavaScript和CSS)構(gòu)建的可以定制瀏覽體驗(yàn)的小型軟件程序。它們使用戶可以根據(jù)個(gè)人需要或偏好來定制Chrome功能和行為。
要想開發(fā)一款瀏覽器插件,我們只需要有一個(gè)manifest.json文件即可, 為了快速上手瀏覽器插件開發(fā),我們需要把瀏覽器開發(fā)者工具打開, 具體步驟如下:
- 在谷歌瀏覽器中輸入chrome://extensions/。
- 將開發(fā)者模式啟動(dòng)。
- 導(dǎo)入自己的瀏覽器插件包。
通過以上三個(gè)步驟我們就可以開啟瀏覽器插件開發(fā)之旅了.瀏覽器插件一般放在瀏覽器地址欄右側(cè),我們可以在manifest.json文件配置插件的icon,并配置一定的規(guī)則,就能看到我們的瀏覽器插件圖標(biāo)了,如下圖:
下面我們來具體講解一下瀏覽器插件開發(fā)的核心概念。
2、核心知識(shí)點(diǎn)
瀏覽器插件一般涉及以下幾個(gè)核心文件:
- manifest.json用來配置所有和插件相關(guān)的配置(必須放在根目錄)。
- background.js后臺(tái)腳本(后臺(tái)頁面),生命周期和瀏覽器一致,一般放置全局代碼。
- content-scripts插件向頁面注入腳本的一種形式,我們可以通過content-scripts向頁面注入js和css資源,并可控制允許注入的范圍。
- popup點(diǎn)擊插件圖標(biāo)后打開的自定義窗口, 用來處理用戶交互。
筆者畫了一張簡圖來大致表示一下它們之間的關(guān)系:
接下來我們來具體了解一下以上幾個(gè)核心知識(shí)點(diǎn)。
(1)manifest.json
谷歌官網(wǎng)給我們提供了一份簡單的配置,如下:
{
"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"
}
}各字段含義介紹如下:
- name瀏覽器插件名稱, 將會(huì)在插件列表中顯示。
- description瀏覽器插件簡介, 方便告訴開發(fā)者插件的功能和作用, 將會(huì)在插件列表中顯示。
- version瀏覽器插件版本。
- icon瀏覽器插件圖標(biāo)。
- background背景頁的腳本路徑,一般為插件目錄的相對(duì)地址。
- permissions允許使用的瀏覽器API的權(quán)限,比如contextMenus(右鍵菜單), tabs(操作標(biāo)簽), webRequest(使用web請(qǐng)求), storage(允許使用本地存儲(chǔ)), "http://*"(可以通過executeScript或者insertCSS訪問的網(wǎng)站)。
- browser_action瀏覽器右上角圖標(biāo)設(shè)置(包括popup頁面, 鼠標(biāo)懸停時(shí)的標(biāo)題, icon等)。
- content_scripts需要直接注入頁面的javascript腳本。
- web_accessible_resources普通頁面能夠直接訪問的插件資源列表,如果不設(shè)置是無法直接訪問的。
- chrome_url_overrides覆蓋瀏覽器默認(rèn)頁面(經(jīng)常用來做瀏覽器的自定義桌面)。
- omnibox向地址欄注冊(cè)一個(gè)關(guān)鍵字以提供搜索建議,只能設(shè)置一個(gè)關(guān)鍵字(多用于自定義搜索攔截)。
- default_locale默認(rèn)語言(比如"zh_CN")。
(2)background.js
background頁面主要用來提供一些全局配置, 事件監(jiān)聽, 業(yè)務(wù)轉(zhuǎn)發(fā)等.舉幾個(gè)常用案例:
定義右鍵菜單。
// background.jsconst 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"]}效果如下:
設(shè)置只有.com后綴的頁面才會(huì)激活插件。
chrome.runtime.onInstalled.addListener(function() {
// 類似于什么時(shí)候激活瀏覽器插件圖標(biāo)這種感覺
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([{
conditions: [new chrome.declarativeContent.PageStateMatcher({
pageUrl: {hostSuffix: '.com'},
})
],
actions: [new chrome.declarativeContent.ShowPageAction()]
}]);
});
});如下圖所示,當(dāng)頁面地址的后綴不等于.com時(shí),插件icon將不被激活:
和content_script或者popup頁面進(jìn)行消息通信。
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"});
});
(3)content-scripts
內(nèi)容腳本一般植入會(huì)被植入到頁面中, 并且可以控制頁面中的dom. 我們可以利用它實(shí)現(xiàn)屏蔽網(wǎng)頁廣告, 定制頁面皮膚等操作. 在manifest.json中的基本配置如下:
{
"content_scripts": [{
"matches": [
"http://*/*",
"https://*/*"
],
"js": [
"lib/jquery3.4.min.js",
"content_script.js"
],
"css": ["base.css"]
}],
}以上代碼中我們定義了content_scripts允許注入的頁面范圍, 插入頁面的js以及css, 這樣我們就能輕松改變某一個(gè)頁面的樣式.比如我們可以在頁面中注入一個(gè)按鈕:
在后面的瀏覽器插件案例中筆者會(huì)詳細(xì)介紹content_scripts的用法。
(4)popup
popup是用戶點(diǎn)擊插件圖標(biāo)時(shí)打開的一個(gè)小窗口,當(dāng)失去焦點(diǎn)后窗口就立即關(guān)閉,我們一般用它來處理一些簡單的用戶交互和插件說明。
由于popup窗口也是一個(gè)網(wǎng)頁,所以我們一般會(huì)建立一個(gè)popup.html和popup.js用來控制popup的頁面展示和交互.我們?cè)趍anifest.json中配置如下:
{
"page_action": {
"default_title": "小夕圖片提取插件",
"default_popup": "popup.html"
},
}這里要注意一點(diǎn)的是,我們?cè)趐opup.html中不能直接使用script腳本,需要用引入腳本文件的方式.如下:
在線圖片提取工具
以下是筆者寫的一個(gè)插件的popup頁面:
3、通信機(jī)制
對(duì)于一個(gè)相對(duì)復(fù)雜的瀏覽器插件來說,我們不僅僅只操作dom或者提供基本的功能就行了,我們還需要向第三方或者自己的服務(wù)器抓取有用的頁面數(shù)據(jù),這個(gè)時(shí)候就需要用到插件的通信機(jī)制了.因?yàn)閏ontent_script腳本存在于當(dāng)前頁面,受同源策略影響,導(dǎo)致我們無法將捕獲到的數(shù)據(jù)傳給第三方平臺(tái)或者自己的服務(wù)器, 所以我們需要基于瀏覽器的通信API.以下是谷歌瀏覽器插件的通信流程:
(1)popup和background相互通信
由官方文檔可知popup可以直接訪問background頁的方法,所以popup可以直接與其通信:
// background.js
var getData = (data) => { console.log('拿到數(shù)據(jù):' + data) }
// popup.js
let bgObj = chrome.extension.getBackgroundPage();
bgObj.getData(); // 訪問bg的函數(shù)
復(fù)制代碼
3.2 popup或者background頁和content_script通信
這里我們使用chrome的tabs API,如下:// popup.js
// 發(fā)送消息給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接收和發(fā)送消息:
// 接收消息
chrome.runtime.onMessage.addListener(
function(message, sender, sendResponse) {
if (message == "activeBtn"){
// ...
sendResponse({farewell: "激活成功"});
}
});
// 主動(dòng)發(fā)送消息
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
console.log(response, document.body);
// document.body.style.backgroundColor="orange"
});
復(fù)制代碼
有關(guān)消息的長連接,在谷歌官網(wǎng)也寫的很清楚:
我們可以采用如下方式進(jìn)行長連接:
// 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: "太難了."});
});
});
4、數(shù)據(jù)存儲(chǔ)
chrome.storage用來針對(duì)插件全局進(jìn)行數(shù)據(jù)存儲(chǔ),我們?cè)谌魏我粋€(gè)頁面(popup或content_script或background)下存儲(chǔ)了數(shù)據(jù),我們?cè)谝陨先齻€(gè)頁面都可以獲取到, 具體用法如下:
chrome.storage.sync.get('imgArr', function(data) {
console.log(data)
});
// 保存數(shù)據(jù)
chrome.storage.sync.set({'imgArr': imgArr}, function() {
console.log('保存成功');
});
// 另一種方式
chrome.storage.local.set({key: value}, function() {
console.log('Value is set to ' + value);
});
5、應(yīng)用場景
谷歌瀏覽器的插件應(yīng)用場景很多,正如文章開頭的思維導(dǎo)圖中寫的.以下是筆者總結(jié)的一些應(yīng)用場景,大家感興趣可以嘗試去實(shí)現(xiàn):
- 谷歌瀏覽器自定義桌面。
- 網(wǎng)頁性能分析工具。
- 網(wǎng)頁爬蟲。
- 埋點(diǎn)工具。
- 網(wǎng)頁熱力圖生成工具。
- 安全攔截插件。
- 廣告過濾插件。
- 網(wǎng)站動(dòng)態(tài)換膚。
- 第三方數(shù)據(jù)導(dǎo)入。
- 代碼格式化工具。
- 在線協(xié)作工具。
- 防作弊插件。
還有很多實(shí)用工具可以開發(fā),大家可以好好把玩。接下來就來通過實(shí)現(xiàn)一個(gè)網(wǎng)頁圖片提取插件,來總結(jié)以下瀏覽器插件開發(fā)流程。
6、開發(fā)一款抓取網(wǎng)站圖片資源的瀏覽器插件
首先還是按照筆者的風(fēng)格,在開發(fā)任何一種工具之前都要明確需求,所以我們來看看該插件的功能點(diǎn):
- 能植入網(wǎng)頁按鈕,通過點(diǎn)擊按鈕捕獲網(wǎng)頁圖片。
- 能在用戶端展示捕獲的圖片。
- 點(diǎn)擊插件能預(yù)覽捕獲的圖片。
基本上就這幾個(gè)功能,接下來我會(huì)展示核心代碼,在介紹代碼之前我們先預(yù)覽一下插件的實(shí)現(xiàn)效果:
插件目錄結(jié)構(gòu)如下:
因?yàn)椴寮拈_發(fā)比較簡單,所以我直接用jquery開發(fā)。這里我們主要關(guān)注popup.js和content_script.js, popup.js中主要用來獲取從content_script頁傳過來的圖片數(shù)據(jù),并展示在popup.html中,另外又一個(gè)需要注意的是當(dāng)頁面沒有注入生成按鈕時(shí),popupu需要發(fā)送信息給content頁面,主動(dòng)讓其生成按鈕,代碼如下:
chrome.storage.sync.get('imgArr', function(data) {
data.imgArr && data.imgArr.forEach(item => {
var imgWrap = $("")
var img = $("
")
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);
});
});
});對(duì)于content頁面,我們需要實(shí)現(xiàn)的是動(dòng)態(tài)生成按鈕,并且在頁面中植入彈窗來展示獲取到的圖片,另一方面需要將圖片數(shù)據(jù)傳遞給storage,以便popup頁面可以獲取圖片數(shù)據(jù)。
由于頁面比較簡單,筆者就不用過多的第三方庫了,筆者先簡單手寫一個(gè)modal組件,代碼如下:
// 彈窗
~function Modal() {
var modal;
if(this instanceof Modal) {
this.init = function(opt) {
modal = $("");
var title = $("" + opt.title + "");
var close_btn = $("X");
var content = $("");
var mask = $("");
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 || '標(biāo)題',
content: opt.content || ''
}
this.init(options)
modal.show();
}
}
this.hide = function() {
modal.hide();
}
}else {
window.Modal = new Modal()
}
}()
第一步,我們先批量獲取頁面圖片數(shù)據(jù):
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) })因?yàn)閳D片的src路徑可能是相對(duì)地址,所以筆者在這里用正則簡單處理以下,當(dāng)然我們可以進(jìn)行更細(xì)粒度的控制。
第二步,將圖片數(shù)據(jù)存儲(chǔ)到storage中:
chrome.storage.sync.set({'imgArr': imgArr}, function() {
console.log('保存成功');
});第三步,生成預(yù)覽圖片的彈窗,這里用筆者上面實(shí)現(xiàn)的modal組件:
Modal.show({
title: '提取結(jié)果',
content: imgBox
})第四步,當(dāng)popup發(fā)送激活按鈕的通知時(shí),我們要在網(wǎng)頁中動(dòng)態(tài)插入生成按鈕:
chrome.runtime.onMessage.addListener(
function(message, sender, sendResponse) {
if (message == "activeBtn"){
if(!$('.crawl-btn')) {
$('body').append("提取")
}else {
$('.crawl-btn').css("background-color","orange");
setTimeout(() => {
$('.crawl-btn').css("background-color","#06c");
}, 3000);
}
sendResponse({farewell: "激活成功"});
}
});
setTimeout那段純屬是為了吸引用戶視線,當(dāng)然我們可以用更優(yōu)雅的方式來處理。插件核心代碼主要是這些,當(dāng)然還有很多細(xì)節(jié)要考慮,我把配置文件和一些細(xì)節(jié)放到github了,如果感興趣的朋友可以安裝感受一下。
github地址:?https://github.com/MrXujiang。
本文轉(zhuǎn)載自微信公眾號(hào)「趣談前端」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系趣談前端公眾號(hào)。
新聞名稱:30分鐘開發(fā)一款抓取網(wǎng)站圖片資源的瀏覽器插件
當(dāng)前路徑:http://www.dlmjj.cn/article/ccshcce.html


咨詢
建站咨詢
