Chrome 插件特性及實戰場景案例分析

一、前言

提起Chrome擴展插件(Chrome Extension),每個人的瀏覽器中或多或少都安裝了幾個插件,像一鍵翻譯、廣告屏蔽、錄屏等等,通過使用這些插件,可以有效的提高我們的工作效率;但有時候,我們想要的某個功能市面上沒有現成的插件,作為開發者自然而然想到,自己是否可以動手開發一個訂製化的插件?網上目前很多不錯的關於Chrome插件的開發教程,可以幫助我們快速上手開發一個插件, 本文換個思路,從應用著手,通過講解插件的特性來啟發讀者在工作中哪些場景可以通過插件來解決。

本文側重點不是Chrome插件的基礎開發,而是聚焦於原理及應用,會從插件的一些重要特性講起,結合實際的插件案例,來分析這些特性的作用,從而能夠啟發讀者利用這些特性開發出自己的效率工具,打造自己的趁手利器。

二、什麼是Chrome擴展插件

什麼是Chrome擴展插件?在我們印象中,它就像跑在瀏覽器中的應用,可以把瀏覽器想像成手機,那麼插件就像是應用,我們從Chrome應用商店中下載,然後安裝到Chrome瀏覽器中,就可以在瀏覽器中進行運行了。

我們看看官方解釋:

Chrome Extension是一個小的軟體程式,它可以用來定義瀏覽器的瀏覽體驗,讓用戶可以根據個人需求或者偏好訂製Chrome瀏覽器的功能和行為,主要使用的技術棧是HTML、Javascript和CSS。

一句話總結:Chrome擴展插件是用前端的技術棧,來訂製瀏覽器的功能,改善用戶體驗

可能大家還聽過一個詞:Chrome Plugin。翻譯過來是Chrome插件,和Chrome擴展插件很相近,特別容易搞混,那麼他們之間有什麼區別呢?

  • Chrome Extension僅僅是用來增強瀏覽器網頁的功能,它是利用瀏覽器提供的已有功能和和各種API,進行功能組合,從而改善瀏覽器體驗,停留在瀏覽器層面;

  • Chrome Plugin不僅能增強網頁的功能,同時能夠擴展瀏覽器本身的功能;當瀏覽器提供的功能已經無法滿足你的需求,就需要你通過C/C++這樣的編譯語言來擴展瀏覽器的功能,例如我們常用的Flash 插件,Chrome Plugin工作在內核層面。

三、Chrome擴展插件組成及核心機制

3.1 Chrome擴展插件的組成

一個 Chrome 擴展插件通常由 3 類文件組成:

1) 配置文件 manifest.json,用於配置擴展的名稱、版本號、作者、圖標 icon、彈出介面、許可權、腳本路徑等資訊;

2) 圖片、css 等資源文件;

3)js腳本文件,其中包含:

  • popup.js:用於搭配 popup.html 使用,點擊插件圖標的時候展示頁面及頁面邏輯控制;

  • background.js:用於定義一個後台頁面,相當於一個常駐頁面,生命周期和瀏覽器一致;

  • content_scripts.js:用於向頁面中注入 JS 腳本,它可以操作頁面dom,但不會和頁面中的腳本產生衝突。

3.2 Chrome擴展插件的核心機制

Chrome擴展插件中比較核心的幾個概念:Extension Page、background.js、Content_script.js ,它們在什麼時機觸發,扮演著什麼角色,彼此之間如何進行通訊?可以看一下下面的關係圖:

從圖中可以看出,存在三個進程:擴展進程(Extension Process)、頁面渲染進程(Render Process)、瀏覽器進程(Browser Process)。

1)擴展進程中運行Extension Page,Extension Page主要包括backgrount.html和popup.html:

  • backgrount.html中沒有任何內容,是通過background.js創建生成,當瀏覽器打開時,會自動載入插件的background.js文件,它獨立於網頁並且一直運行在後台,它主要通過調用瀏覽器提供的API和瀏覽器進行交互;

  • popup.html則不同,它有內容,是一個實實在在的頁面,和我們普通的web頁面一樣,由html、css、Javascript組成,它是按需載入的,需要用戶去點擊地址欄的按鈕去觸發,才能彈出頁面。

2)渲染進程主要運行Web Page,當打開頁面時,會將content_script.js載入並注入到該網頁的環境中,它和網頁中引入的Javascript一樣,可以操作該網頁的DOM Tree,改變頁面的展示效果;

3)瀏覽器進程在這裡更多起到橋樑作用,作為中轉可以實現Extension Page和Content_script.js之間的消息通訊。

四、Chrome擴展插件能做什麼

Chrome擴展插件的使用方向主要包含兩個部分:

改變瀏覽器的外觀:

  • brower Actions

  • page Actions

  • content menus

  • 桌面通知

  • Omnibox

  • override 替代頁

和瀏覽器進行交互

  • Cookie控制

  • 標籤控制

  • 書籤控制

  • 下載控制

  • 事件監聽

  • 網路請求

  • 代理…

下面我們通過實例來分析這些功能的使用案例:

實例1:替換頁面

使用替代頁,可以將Chrome默認的一些特定頁面替換掉,改為使用擴展提供的頁面。這讓開發者可以開發更多有趣或者實用的基本功能頁面。

 "chrome_url_overrides": {
      "newtab": "newTab.html", //替換新標籤頁
      "bookmarks":"bookmarks.html",   //替換書籤管理器頁面
      "history":"history.html"   //替換歷史記錄頁面
   },

下面是一個替換新標籤頁的效果圖:

實例2:Cookie控制

通過Cookie的API,可以對瀏覽器的Cookie進行增刪改查工作。例如我們在開發工作中,經常需要頻繁的清除瀏覽器快取,每次都需要先找到清除按鈕,彈出對話框,進行確認,操作很繁瑣,如果開發一個chrome擴展插件,就可以輕鬆實現一鍵快捷清除瀏覽器Cookie等快取,可以參考Clear Store插件。

**實例3:標籤控制 **

使用chrome.tabs API與瀏覽器的標籤系統進行交互,可以查詢,創建、修改和重新排列瀏覽器中的標籤頁;我們在使用瀏覽器時,經常會打開很多標籤頁,顯得很混亂,中途想要找打開的某個頁面時,效率低且痛苦,如果能將這些標籤頁進行整理並有序的展示該多好,這裡給大家推薦一個Chrome擴展插件:OneTab,該插件將所有打開的標籤頁在新的頁面中有序的排列出來,如下圖,一目了然。

我們甚至可以通過tabs 實現頁簽之間的交互,出於安全考慮,tab的屬性中沒有document, 因此無法在擴展中直接獲取某個標籤頁面中的dom元素,但是可以通過發送事件請求來實現:

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的元素髮過去
      });
    }
  }
);

實例4:攔截請求或者反向代理

在在頁面性能點檢時,我們經常會檢查頁面圖片資源是否存在尺寸過大,例如200K,獲取一個過大的圖片列表頁面。

chrome.webRequest API只能在background.js中使用,所以可以通過圖片攔截,將鏈接通過消息傳給當前頁面的content_script.js,然後在content_script.js中進行圖片下載和大小檢查。

// background.js
chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    // url就是圖片下載的鏈接
    const { url ,tabId} = details
    // 向content_script.js發送下載圖片鏈接
    chrome.tabs.sendMessage(tabId, {picUrl: url}, function(response) {
       //...
     });
    return {cancel: isCancel};
  },
  {urls: ["//baidu.com"],types: "image"},
  ["blocking"]
);
// content_script.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse)
{
    if(sender.tab && request.picUrl && request.picUrl == sender.tab.id){
       //獲取圖片大小並下載
    }
});

實例5:頁面元素操作

利用Content_script.js可操作dom元素,進行對頁面元素進行操作,實現自動化登錄,解放雙手。

//輸入
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");//按鈕
//輸入後,點擊確認
input(usernameDom, "姓名");
input(pwdDom, "密碼");
//登錄
btnDom.click();

五、業務實踐

痛點:我目前主要負責vivo全球商城的業務,全球化的業務都會面臨國際化語言的問題,我們自主開發了一個多語言管理後台,配置key-value,前端通過介面獲取多語言在頁面展示;如果運營查看頁面,覺得某個文案不太合適,想要修改,需要進行如下圖的一系列操作:

可以看到當運營想要修改文案時,他先要知道該文案對應的key值,而頁面上面無法獲取到key值,需要讓開發提供,然後需要到多語言管理平台去更新對應key的值。

這樣遇到兩個問題:

  • 不能所見即所得,看到頁面不能知道key值;

  • 所見無法直接修改,需要到另一個管理平台去修改 ;

目前這個在修改內容少的情況下,還是可以操作的,當修改內容很多時,這樣操作起來很繁瑣,效率很低。

思考:

1)運營是否可以直接在頁面上修改並生效?

2)如果可以修改,怎麼去實現跨域請求?

3)怎麼實現登錄授權?

如果對Chrome擴展插件熟悉,會發現Chrome就是為這量身訂製,可以完美解決這些問題。

**實現方案: **

1)對頁面中涉及文案dom進行修改,綁定多語言key值。

<div data-lang-key="address.delete.button">{{ language.addressDeleteButton }}</div>

2)利用Content_script,js可以操作頁面dom元素,當啟動插件時,將頁面所有可修改的文案的dom增加contenteditable屬性,支援可編輯,如圖;

3)創建一個修改面板,獲取當前選中的key值和value值,和修改後的值,如上圖,右上角面板。

4)利用Chrome插件支援跨站請求的特性,向多語言平台直接發送修改請求。

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特性,新開一個標籤頁打開多語言後台,進行登錄,登錄成功後就可以實現請求的授權修改了。

六、總結

最後總結一下,生活中經常會感嘆:看過好多人生道理,依然過不好這一生。同樣,使用過很多Chrome插件,依然碼不好自己的一個插件,所以最後再送給你一個閱讀Chrome插件源碼的插件,堪稱插件中的插件,插件中的王者——Chrome extension source viewer。通過它可以很方便的查看其它插件的源碼,讓我們能夠站在巨人的肩膀上往前走~~

作者:vivo互聯網前端團隊-Zhang hao