一、前言
提起Chrome擴(kuò)展插件(Chrome Extension),每個人的瀏覽器中或多或少都安裝了幾個插件,像一鍵翻譯、廣告屏蔽、錄屏等等,通過使用這些插件,可以有效的提高我們的工作效率;但有時候,我們想要的某個功能市面上沒有現(xiàn)成的插件,作為開發(fā)者自然而然想到,自己是否可以動手開發(fā)一個定制化的插件?網(wǎng)上目前很多不錯的關(guān)于Chrome插件的開發(fā)教程,可以幫助我們快速上手開發(fā)一個插件, 本文換個思路,從應(yīng)用著手,通過講解插件的特性來啟發(fā)讀者在工作中哪些場景可以通過插件來解決。
本文側(cè)重點(diǎn)不是Chrome插件的基礎(chǔ)開發(fā),而是聚焦于原理及應(yīng)用,會從插件的一些重要特性講起,結(jié)合實(shí)際的插件案例,來分析這些特性的作用,從而能夠啟發(fā)讀者利用這些特性開發(fā)出自己的效率工具,打造自己的趁手利器。
二、什么是Chrome擴(kuò)展插件
什么是Chrome擴(kuò)展插件?在我們印象中,它就像跑在瀏覽器中的應(yīng)用,可以把瀏覽器想象成手機(jī),那么插件就像是應(yīng)用,我們從Chrome應(yīng)用商店中下載,然后安裝到Chrome瀏覽器中,就可以在瀏覽器中進(jìn)行運(yùn)行了。
我們看看官方解釋:
Chrome Extension是一個小的軟件程序,它可以用來定義瀏覽器的瀏覽體驗(yàn),讓用戶可以根據(jù)個人需求或者偏好定制Chrome瀏覽器的功能和行為,主要使用的技術(shù)棧是HTML、Javascript和CSS。
一句話總結(jié):Chrome擴(kuò)展插件是用前端的技術(shù)棧,來定制瀏覽器的功能,改善用戶體驗(yàn)。
可能大家還聽過一個詞:Chrome Plugin。翻譯過來是Chrome插件,和Chrome擴(kuò)展插件很相近,特別容易搞混,那么他們之間有什么區(qū)別呢?
Chrome Extension僅僅是用來增強(qiáng)瀏覽器網(wǎng)頁的功能,它是利用瀏覽器提供的已有功能和和各種API,進(jìn)行功能組合,從而改善瀏覽器體驗(yàn),停留在瀏覽器層面;
- Chrome Plugin不僅能增強(qiáng)網(wǎng)頁的功能,同時能夠擴(kuò)展瀏覽器本身的功能;當(dāng)瀏覽器提供的功能已經(jīng)無法滿足你的需求,就需要你通過C/C++這樣的編譯語言來擴(kuò)展瀏覽器的功能,例如我們常用的Flash 插件,Chrome Plugin工作在內(nèi)核層面。
三、Chrome擴(kuò)展插件組成及核心機(jī)制
3.1 Chrome擴(kuò)展插件的組成
一個 Chrome 擴(kuò)展插件通常由 3 類文件組成:
1) 配置文件 manifest.json,用于配置擴(kuò)展的名稱、版本號、作者、圖標(biāo) icon、彈出界面、權(quán)限、腳本路徑等信息;
2) 圖片、css 等資源文件;
3)js腳本文件,其中包含:
popup.js:用于搭配 popup.html 使用,點(diǎn)擊插件圖標(biāo)的時候展示頁面及頁面邏輯控制;
background.js:用于定義一個后臺頁面,相當(dāng)于一個常駐頁面,生命周期和瀏覽器一致;
- content_scripts.js:用于向頁面中注入 JS 腳本,它可以操作頁面dom,但不會和頁面中的腳本產(chǎn)生沖突。
3.2 Chrome擴(kuò)展插件的核心機(jī)制
Chrome擴(kuò)展插件中比較核心的幾個概念:Extension Page、background.js、Content_script.js ,它們在什么時機(jī)觸發(fā),扮演著什么角色,彼此之間如何進(jìn)行通信?可以看一下下面的關(guān)系圖:
從圖中可以看出,存在三個進(jìn)程:擴(kuò)展進(jìn)程(Extension Process)、頁面渲染進(jìn)程(Render Process)、瀏覽器進(jìn)程(Browser Process)。
1)擴(kuò)展進(jìn)程中運(yùn)行Extension Page,Extension Page主要包括backgrount.html和popup.html:
backgrount.html中沒有任何內(nèi)容,是通過background.js創(chuàng)建生成,當(dāng)瀏覽器打開時,會自動加載插件的background.js文件,它獨(dú)立于網(wǎng)頁并且一直運(yùn)行在后臺,它主要通過調(diào)用瀏覽器提供的API和瀏覽器進(jìn)行交互;
- popup.html則不同,它有內(nèi)容,是一個實(shí)實(shí)在在的頁面,和我們普通的web頁面一樣,由html、css、Javascript組成,它是按需加載的,需要用戶去點(diǎn)擊地址欄的按鈕去觸發(fā),才能彈出頁面。
2)渲染進(jìn)程主要運(yùn)行Web Page,當(dāng)打開頁面時,會將content_script.js加載并注入到該網(wǎng)頁的環(huán)境中,它和網(wǎng)頁中引入的Javascript一樣,可以操作該網(wǎng)頁的DOM Tree,改變頁面的展示效果;
3)瀏覽器進(jìn)程在這里更多起到橋梁作用,作為中轉(zhuǎn)可以實(shí)現(xiàn)Extension Page和Content_script.js之間的消息通信。
四、Chrome擴(kuò)展插件能做什么
Chrome擴(kuò)展插件的使用方向主要包含兩個部分:
改變?yōu)g覽器的外觀:
brower Actions
page Actions
content menus
桌面通知
Omnibox
- override 替代頁
和瀏覽器進(jìn)行交互:
Cookie控制
標(biāo)簽控制
書簽控制
下載控制
事件監(jiān)聽
網(wǎng)絡(luò)請求
- 代理...
下面我們通過實(shí)例來分析這些功能的使用案例:
實(shí)例1:替換頁面
使用替代頁,可以將Chrome默認(rèn)的一些特定頁面替換掉,改為使用擴(kuò)展提供的頁面。這讓開發(fā)者可以開發(fā)更多有趣或者實(shí)用的基本功能頁面。
"chrome_url_overrides": { "newtab": "newTab.html", //替換新標(biāo)簽頁 "bookmarks":"bookmarks.html", //替換書簽管理器頁面 "history":"history.html" //替換歷史記錄頁面 },
下面是一個替換新標(biāo)簽頁的效果圖:
實(shí)例2:Cookie控制
通過Cookie的API,可以對瀏覽器的Cookie進(jìn)行增刪改查工作。例如我們在開發(fā)工作中,經(jīng)常需要頻繁的清除瀏覽器緩存,每次都需要先找到清除按鈕,彈出對話框,進(jìn)行確認(rèn),操作很繁瑣,如果開發(fā)一個chrome擴(kuò)展插件,就可以輕松實(shí)現(xiàn)一鍵快捷清除瀏覽器Cookie等緩存,可以參考Clear Store插件。
實(shí)例3:標(biāo)簽控制?
使用chrome.tabs API與瀏覽器的標(biāo)簽系統(tǒng)進(jìn)行交互,可以查詢,創(chuàng)建、修改和重新排列瀏覽器中的標(biāo)簽頁;我們在使用瀏覽器時,經(jīng)常會打開很多標(biāo)簽頁,顯得很混亂,中途想要找打開的某個頁面時,效率低且痛苦,如果能將這些標(biāo)簽頁進(jìn)行整理并有序的展示該多好,這里給大家推薦一個Chrome擴(kuò)展插件:OneTab,該插件將所有打開的標(biāo)簽頁在新的頁面中有序的排列出來,如下圖,一目了然。
我們甚至可以通過tabs 實(shí)現(xiàn)頁簽之間的交互,出于安全考慮,tab的屬性中沒有document, 因此無法在擴(kuò)展中直接獲取某個標(biāo)簽頁面中的dom元素,但是可以通過發(fā)送事件請求來實(shí)現(xiàn):
chrome.tabs.sendRequest(tab_id, { hello: "ok" }, function(response){ // response處理});
chrome.extension.onRequest.addListener( function(request, sender, sendResponse) { if (request.hello == "ok"){ sendResponse({ data: $("#hello") // 獲取id是hello的元素發(fā)過去 }); } });
實(shí)例4:攔截請求或者反向代理
在在頁面性能點(diǎn)檢時,我們經(jīng)常會檢查頁面圖片資源是否存在尺寸過大,例如200K,獲取一個過大的圖片列表頁面。
chrome.webRequest API只能在background.js中使用,所以可以通過圖片攔截,將鏈接通過消息傳給當(dāng)前頁面的content_script.js,然后在content_script.js中進(jìn)行圖片下載和大小檢查。
// background.jschrome.webRequest.onBeforeRequest.addListener( function(details) { // url就是圖片下載的鏈接 const { url ,tabId} = details // 向content_script.js發(fā)送下載圖片鏈接 chrome.tabs.sendMessage(tabId, {picUrl: url}, function(response) { //... }); return {cancel: isCancel}; }, {urls: ["http://baidu.com"],types: "image"}, ["blocking"]);
// content_script.jschrome.runtime.onMessage.addListener(function(request, sender, sendResponse){ if(sender.tab && request.picUrl && request.picUrl == sender.tab.id){ //獲取圖片大小并下載 }});
實(shí)例5:頁面元素操作
利用Content_script.js可操作dom元素,進(jìn)行對頁面元素進(jìn)行操作,實(shí)現(xiàn)自動化登錄,解放雙手。
//輸入function input(inputElement, content) { let event = document.createEvent(HTMLEvents); event.initEvent(input, true, true); inputElement.value = content; inputElement.dispatchEvent(event)}const usernameDom = document.getElementById("userName"); //用戶名const pwdDom = document.getElementById("password"); //密碼const btnDom = document.getElementById("submitBtn");//按鈕//輸入后,點(diǎn)擊確認(rèn)input(usernameDom, "姓名");input(pwdDom, "密碼");//登錄btnDom.click();
五、業(yè)務(wù)實(shí)踐
痛點(diǎn):我目前主要負(fù)責(zé)vivo全球商城的業(yè)務(wù),全球化的業(yè)務(wù)都會面臨國際化語言的問題,我們自主開發(fā)了一個多語言管理后臺,配置key-value,前端通過接口獲取多語言在頁面展示;如果運(yùn)營查看頁面,覺得某個文案不太合適,想要修改,需要進(jìn)行如下圖的一系列操作:
可以看到當(dāng)運(yùn)營想要修改文案時,他先要知道該文案對應(yīng)的key值,而頁面上面無法獲取到key值,需要讓開發(fā)提供,然后需要到多語言管理平臺去更新對應(yīng)key的值。?
這樣遇到兩個問題:
不能所見即所得,看到頁面不能知道key值;
- 所見無法直接修改,需要到另一個管理平臺去修改 ;
目前這個在修改內(nèi)容少的情況下,還是可以操作的,當(dāng)修改內(nèi)容很多時,這樣操作起來很繁瑣,效率很低。
思考:
1)運(yùn)營是否可以直接在頁面上修改并生效?
2)如果可以修改,怎么去實(shí)現(xiàn)跨域請求?
3)怎么實(shí)現(xiàn)登錄授權(quán)?
如果對Chrome擴(kuò)展插件熟悉,會發(fā)現(xiàn)Chrome就是為這量身定制,可以完美解決這些問題。
實(shí)現(xiàn)方案:?
1)對頁面中涉及文案dom進(jìn)行修改,綁定多語言key值。
{{ language.addressDeleteButton }}
2)利用Content_script,js可以操作頁面dom元素,當(dāng)啟動插件時,將頁面所有可修改的文案的dom增加contenteditable屬性,支持可編輯,如圖;
3)創(chuàng)建一個修改面板,獲取當(dāng)前選中的key值和value值,和修改后的值,如上圖,右上角面板。
4)利用Chrome插件支持跨站請求的特性,向多語言平臺直接發(fā)送修改請求。
chrome.runtime.onMessage.addListener( function(request, sender, sendResponse) { var xhr = new XMLHttpRequest(); xhr.open("POST", url, true); xhr.setRequestHeader(Content-Type, application/x-www-form-urlencoded); xhr.onreadystatechange = function () { if (xhr.readyState == 4) { try{ sendResponse(JSON.parse(xhr.response)); }catch(e) { // 異常處理 } } }; xhr.send(new URLSearchParams(params)); return true });
5)利用Chrome插件可以獲取瀏覽器中Cookie特性,新開一個標(biāo)簽頁打開多語言后臺,進(jìn)行登錄,登錄成功后就可以實(shí)現(xiàn)請求的授權(quán)修改了。
六、總結(jié)
最后總結(jié)一下,生活中經(jīng)常會感嘆:看過好多人生道理,依然過不好這一生。同樣,使用過很多Chrome插件,依然碼不好自己的一個插件,所以最后再送給你一個閱讀Chrome插件源碼的插件,堪稱插件中的插件,插件中的王者——Chrome extension source viewer。通過它可以很方便的查看其它插件的源碼,讓我們能夠站在巨人的肩膀上往前走~~
作者:vivo互聯(lián)網(wǎng)前端團(tuán)隊(duì)-Zhang hao