Chrome擴展開發科普

1. chrome 擴展是什麼

chrome 擴展是用傳統的 HTML、CSS、JS、圖片等靜態資源開發並最終打包成後綴爲 .crx 的一個壓縮包。因此,它和咱們日常開發的頁面沒有多大的區別,因此若是你想引入前端開發所用的各類框架,組件庫,構建工具也都是能夠的。主要區別只有 2 個:javascript

  1. 擴展的頁面、js 和普通的頁面運行位置不一樣
  2. 擴展能夠調用 chrome 提供的更多的 API 來加強咱們擴展的能力

2. chrome 擴展的安裝方式

擴展的安裝方式有 3 種:css

  1. 經過 chrome 擴展商店,下載安裝
  2. 在其餘網站下載打包好的 .crx 壓縮包,把壓縮包直接拖拽到 chrome 的擴展管理頁面
  3. 若是是本身開發的擴展,能夠在擴展管理頁面,打開開發者模式,手動加載已解壓的擴展程序,進行本地調試

3. chrome 擴展的展示形式

這裏只簡單地介紹幾種常常見到的,還有更多的展示形式,你們感興趣能夠去官方文檔詳細瞭解html

  1. 點擊地址欄右側 icon 會有頁面彈出,這個大多數擴展都會有,主要是擴展的設置或者功能的入口
  2. 頁面修飾內容:經過添加 DOM 對頁面賦予新功能,好比 Octotree (對 gitub 項目頁面作導航)
  3. 頁面右鍵菜單:定製在頁面內右鍵彈出的菜單,不少劃線翻譯的擴展都利用了這個功能
  4. 覆蓋 chrome 默認頁面: chrome 有的頁面支持開發者自定義,好比 Momentum 就覆蓋了默認的 New Tab 頁面
  5. devtool 工具:這個是開發者常常用到的 好比 vue-devtool 等框架提供的調試工具

4. 開發介紹

具體擴展各個組成部分的學習,咱們以一個很簡單的例子爲基礎進行介紹,這個擴展是一個爲頁面添加回到頂部功能的擴展。前端

4.1 配置文件

每個擴展都必需要有的一個名字爲 manifest.json 的配置文件,這個文件聲明瞭此擴展用到了哪些功能,及各個功能須要用到的靜態資源vue

這個 backToTop 擴展的配置已經在途中說明,已經有了基本的說明,下面對一些配置項作下額外的說明,所有配置能夠在官網查看:java

  1. browser_action 指定了 popup 頁面相關的 icon、html、tooltip 文字等配置,類似的還有一個 page_action,它的配置參數和 browser_aciton 是相同的 可是它能夠經過 chrome.pageAction API 來動態的設置擴展在某些頁面的行爲
  2. icons 配置不用每一個尺寸都給出,chrome 會本身選出效果最合適的 icon
  3. permissions 聲明擴展須要用到的 chrome 特性

5. 經常使用 API

  1. chrome.runtime
  2. chrome.tabs 對標籤頁進行操做、與對應標籤頁內容通信
  3. chrome.storage 擴展的存儲,相似 localstorage
  4. chrome.contextMenus
  5. chrome.extension

6. 核心 JS

這部分咱們說下擴展開發核心的幾種 JSgit

6.1 popup

popup 頁面生命週期是點擊彈出時,初始化,關閉時,頁面也跟着銷燬, 而且這個頁面沒有任何跨域的限制。它在咱們擴展裏的做用是配置頁面裏 backToTop icon 的樣式,並存入storage。web

chrome.storage.local.get(['right', 'bottom', 'icon'], function(result) {
  if(result) {
    // 初始化
    right.value = result.right || '';
    bottom.value = result.bottom || '';
    if(result.icon) {
      img.src = result.icon;
      img.dataset.uploaded = true;
    }
  }
})
複製代碼

頁面初始化時,從 storage 取出存儲的值,初始化頁面。 保存參數時,再將相關參數存入 storagechrome

chrome.storage.local.set({right: rightVal, bottom: bottomVal});
  if(img.dataset.uploaded) {
    chrome.storage.local.set({icon: img.src});
  }
複製代碼

注: storage API 有 2 種 storage.syncstorage.local 他們的區別json

  1. sync 會將存儲的數據定時發到 chrome 的服務器,進行數據的同步,local 就只是將數據存儲在本地
  2. 尺寸的不一樣:local 和 localstorage 是同樣的 5M. 而 sync 存儲的大小隻有 100K 並且對於單個 key 的值大小,以及寫入的頻率也有限制,畢竟要同步服務端,因此若是開發的擴展只是用於我的使用的效率提高,不打算髮布,能夠直接用 local 就行了

6.2 content-script

content-script 是咱們用來定製化頁面,實現頁面內擴展邏輯的地方。它的特色是:

  1. 由於在頁面內,固然能夠訪問 DOM 可是和頁面的 js 是徹底獨立的,不能互相訪問
  2. 沒法對頁面內的 DOM 事件綁定 擴展裏的回調,這種狀況能夠經過 content-script 建立一個 script 標籤插入到 DOM 裏 這個新的 script 裏的函數是能夠綁定的
  3. 由於在頁面裏運行,因此是會收到跨域限制滴
  4. 運行時機是隨着頁面的加載而運行,頁面關閉也就卸載了,因此說 content-script 會在每個 tab 頁面裏都有一份代碼在運行
  5. 由於在頁面初始化纔會運行,因此在初始加載插件時,須要刷新頁面,content-script 纔會開始運行。
  6. 注入頁面的 css 優先級很是高,必定要注意好類名 ID 名的設置

那咱們的 backToTop 裏 content-script 都幹了什麼呢 首先,初始化咱們頁面裏的 icon 並根據頁面 scrollTop 判斷當前是否須要展現 icon

const el = document.createElement('div');
el.show = true; // 控制icon是否顯示
el.classList.add('ce-btt-container');


el.style.opacity = target.scrollTop > visibleHeight ? 1 : 0;

const img = document.createElement('img');
img.classList.add('ce-btt-icon');

el.appendChild(img);


chrome.storage.local.get(['right', 'bottom', 'icon'], function(result) {
  el.style.right = result && result.right ? result.right + 'px' : right;
  el.style.bottom = result && result.bottom ?  result.bottom + 'px' : bottom;
  img.src = result && result.icon ? result.icon : chrome.runtime.getURL('icons/backToTop.png');
  document.body.appendChild(el);
});
複製代碼

第二步, 要想實現返回頂部,固然要給咱們的 icon 綁定點擊事件,以及監聽 scroll 事件判斷何時該隱藏展現

el.addEventListener('click', function(e) {
  let step = 20;
  let timer = setInterval(() => {
    if(target.scrollTop <= 0) {
      clearInterval(timer);
    } else {
      step += 20;
      target.scrollTop -= step;
    }
  }, 20);
});

const handleScroll = function() {
  if(!el.show) return false;  // icon不顯示時,不處理
  if(target.scrollTop > visibleHeight) {
    el.style.opacity = 1;
  } else {
    el.style.opacity = 0;
  }
};

container.addEventListener('scroll', throttle(handleScroll, 300));
複製代碼

第三步, 若是 popup 頁面有配置的變動, content-script 都須要馬上進行更新

chrome.storage.onChanged.addListener(function(changes, namespace) {
  if(changes.bottom) {
    el.style.bottom = `${changes.bottom.newValue}px`;
  }
  if (changes.right) {
    el.style.right = `${changes.right.newValue}px`;
  }
  if (changes.icon) {
    img.src = changes.icon.newValue;
  }
});
複製代碼

注: 這裏須要注意的是,由於咱們要把擴展裏的 icon 插入到頁面,因此須要在 manifest.json 裏配置 web_accessible_resources 賦予頁面能夠訪問咱們指定的擴展靜態資源的權限。這是由於頁面裏 icon 的 src 屬性是這樣的

6.3 background

background 能夠理解爲是擴展在後臺一直運行的一個 JS(實際並非), 它在整個瀏覽器裏只會有一個 js 在運行。在 background 的配置裏,有一個 persistent 的配置, 當它爲 true 時,background 纔會一直運行,false 時,瀏覽器會檢測長時間不活動時,自動卸載調,只有監聽的事件發生時,纔會從新執行,官方的說明是

The only occasion to keep a background script persistently active is if the extension uses chrome.webRequest API to block or modify network requests. The webRequest API is incompatible with non-persistent background pages.

因此絕大多數時候,咱們把它設爲 false 就能夠了。另外 background 也是能夠跨域的, 因此咱們能夠總結出,除了頁面內的 js chrome 對其餘的 js 都沒有跨域的限制。

好,咱們看看咱們擴展裏 background 幹了啥

首先,初始時,確定要監聽瀏覽器的初始化事件,才能夠綁定擴展關注的事件。

chrome.runtime.onInstalled.addEventListener(function() {
  // init extention
})
複製代碼

第二步,由於有的頁面已經提供了返回頂部的功能,因此這個時候咱們須要提供能夠把咱們的 icon 永久隱藏的功能,咱們在 background 初始化的邏輯中,建立一個鼠標右鍵的菜單項,這個菜單項能夠實現 切換咱們的 icon 顯示狀態的功能

chrome.contextMenus.create({
    title: 'toggle',
    id: 'toggle'
  });

chrome.contextMenus.onClicked.addListener(function() {
  chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    sendMsg(tabs.length ? tabs[0].id : null);
  });
});

function sendMsg(tabId) {
  chrome.tabs.sendMessage(tabId, 'toggle', function(res) {
    console.log(res);
  });
}
複製代碼

發送消息這裏咱們用了 chrome.tabs API 由於咱們每一個 tab 都會有一個 content-script 因此須要篩選出當前所在的標籤頁,而後發送消息。

最後,咱們的 content-script 須要監聽發送消息的事件,並切換 icon 的狀態

chrome.runtime.onMessage.addListener(function(req, sender, respond) {
  if(req === 'toggle') {
    if (target.scrollTop > visibleHeight) {
      el.style.opacity = el.style.opacity === '1' ? 0 : 1;
    }
    el.show = !el.show;
    respond('toggle success');
  }
});
複製代碼

至此,整個擴展的功能就基本介紹完了,過程當中用到的 API 這裏並不做詳細的介紹,詳細使用仍是須要你們去 官網 查看

6.4 調試

最後說一下如何調試,調試我的認爲仍是比較麻煩的, 代碼變動並無熱更新,因此須要咱們手動去擴展管理頁從新加載。並且幾種不一樣的 JS 調試的位置也不一樣,設計通信時常常須要在幾個不一樣的地方來回切換

popup 調試:在彈出的窗口裏,右鍵審查元素就能夠彈出調試窗口,調試方式和普通的頁面調試沒有區別。

background 調試: 在管理頁點擊背景頁,就能夠彈出調試窗口了

content-script 調試: 由於是在頁面運行,因此調試的地方和頁面 js 是在一個窗口裏

代碼位置:在 sources tab 下選中 Content scripts 就能夠看到頁面加載的所有的擴展 contnt-script 了。

console 輸出: 在 Console tab 下拉框裏選中要調試的擴展,就能夠看到對應擴展的 console 輸出。

7. 打包發佈

在擴展管理頁,能夠打包擴展程序,打包後就能夠生成 .crx 文件

打包以後,就能夠發佈了,不過發佈須要先花 5$ 註冊開發者,我就沒有繼續下去了。

總結

在開發過程當中,能夠發現寫一個擴展其實並不難,用到的技術都是前端天天都在用的東西。只要咱們多加留心,就會發現使用 chrome 過程當中有許多能夠提效,優化體驗的地方,這時候咱們就能夠試着用擴展的方式解決。整體來講,chrome 擴展是一種技術成本很低,就能夠幹些有趣的事情的技術

參考資料:

官方文檔

Chrom插件開發全攻略

相關文章
相關標籤/搜索