一、前言

提起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