看完前更兩篇入門介紹, 相信你對 ChrExt 已經有些基本的概念了。我們現在再來介紹其它較為深入的應用。
前面曾經提過, 我們有幾種方法可以觸發我們寫在 ChrExt 的功能。但是到底應該怎麼寫才對? 我在下面做個清楚的整理。
啟動後立即執行
所謂的「啟動」, 指的是 ChrExt 被開啟。以「Google 翻譯」這個 ChrExt 為例, 一旦你在「擴充功能」頁面中將它開啟(如同下圖所示), 就會立即執行你寫在 ChrExt 裡的指令。
以這種方式啟動的 ChrExt, 你會在它的項目文字裡看到「背景頁面」連結, 進入之後可以看到一個除錯工具, 就像你在平常的網頁中按下 F12 一樣。這個除錯工具是個獨立的視窗, 我們可以方便地進行除錯。如果你把一些資訊以 console.log() 方式輸出, 都可以在裡面的 Console 頁籤下看到結果。
不過, 首先, 你必須在 menifest.json 檔案中加入 "background" 區段:
"background": {
"scripts": [
"Util.js",
"background.js"
]
},
請把你在該功能會載入的檔案都加上去。如果你會用到 jQuery, 也要記得放在這裡。
在上面的範例中, Util.js 是我自己寫的公用程式, background.js 則是我們要讓該 ChrExt 載入後立即執行的功能。它沒有什麼強制的寫法, 就像一般的 JavaScript 檔案一樣, 你寫什麼它就執行什麼。
或許我們應該自問, 你會在這裡執行什麼功能? 一般我們都是在特定網頁載入後才執行某些特定的功能; 似乎很少有什麼事情必須在載入 ChrExt 時會執行的。許多 ChrExt 也都不會在載入時執行什麼, 所以它們並不會有如上圖中所示的「背景頁面」連結。
事實上, 在某些情境下, 如果你在 ChrExt 載入後就執行一些指令, 確實可以提供一些便利性。例如, 你可以事先下載一些較大的資料, 而不是在目的網頁載入時才去下載, 那麼就可以為使用者省下許多寶貴的時間。
載入目的網頁後執行
這裡所謂的「目的網頁」, 指的就是你希望你的 ChrExt 發生作用的那些網頁。如果你希望你的 ChrExt 作用於所有網頁, 那麼所有網頁都可以算是目的網頁。
這些目的網頁必須明確地寫在 menifest.json 裡的 content_scripts 區段裡:
"content_scripts": [
{
"matches": [
"https://www.microsoft.com/*",
"http://www.google.com/*"
]
,"js": [
"Util.js",
"content_script.js"
]
,"run_at": "document_idle"
}
]
此外, 還有 menifest.json, 和上一段做法一樣, 就不贅述了。
當然, 上面只是範例, 我相信你應該不太可能在辛辛苦苦學了 ChrExt 這種艱澀又冷門的主題後, 卻只是寫一些無聊的東西去套用在 Microsoft 和 Google 網頁上。但不管你指定的網頁是什麼, 當他們被載入之後, 你的指令就會被執行。如同我在前面兩篇裡寫過的, 你可以很容易地操作該網頁上的各個元素, 就好像在操作你自己的網頁一樣。
如上範例, 你的指令都寫在 content_script.js 裡。我個人是比較習慣遵照官方範例的寫法:
function initContentScript() {
doBackgroundJob();
}
initContentScript();
真正要執行的功能則是寫在 doBackgroundJob() 函式裡 (不一定要取這個名字)。但是 initContentScript 這個函式名稱不能改, 否則寫得再多也不會執行。
當然, 你並不一定要再多寫一個 doBackgroundJob() 函式; 你大可以把程式通通寫在 initContentScript() 裡, 你寫什麼就會執行什麼。但是我建議你按照上面的方式寫, 因為那跟下一個功能有關係。
按下圖示後執行
如同我在第一篇入門文章寫提到的, 我們可以在按下該 ChrExt 圖示後觸發動作:
這個動作的指令一樣是寫在 content_script.js 裡。其它的動作和上一個範例一模一樣, 只需要稍為修改 content_script.js 即可:
function onExtensionMessage(request) {
if (request==undefined) {
return;
}
if (request['myExt'] != undefined) {
if (!document.hasFocus()) {
return;
}
proceed();
}
}
function initContentScript() {
doBackgroundJob();
chrome.extension.onMessage.addListener(function(msg, sender, sendResponse) {
if (msg.action == 'myExt') {
if (proceed())
sendResponse({ successful: true });
else
sendResponse({ successful: false });
}
});
}
initContentScript();
把上面這一段程式原封不動地抄進去。只有幾個地方要改:
- 把 "myExt" 這個字改成你自己的 ChrExt 的名稱。
- 寫一個 proceed() 函式 (也不一定要使用這個名稱), 在裡面寫使用按下圖示後要觸發的動作。
- 如果你在載入網頁時會執行什麼動作, 可以保留 doBackgroundJob()。但如果沒有, 把它移除即可。
再說一次。按照上面的寫法, 什麼動作就寫在什麼函式裡:
- 載入目的網頁後會自動執行寫在 doBackgroundJob() 裡面的指令
- 載入目的網頁後再按下右上角圖示, 會執行寫在 proceed() 裡面的指令。
這樣清楚了嗎?
不同網頁執行不同動作
其實這裡要講的和 ChrExt 沒有直接的關係; 只是怕剛接觸 ChrExt 的朋友搞不清楚而已。
如果你的目的網頁不只一個, 就像在上面的範例一樣, 如果你希望使用者載入 Microsoft 官網時做一種動作, 載入 Google 官網時做另一種動作, 那麼你必須自行判斷。
如果按照我自己的做法,
let url = document.URL;
if (url.startsWith('https://www.microsoft.com')) {
...
}
if (url.startsWith('https://www.google.com')) {
...
}
當然, 再提醒一次, 這些網頁都必須事先於 manifest.json 裡詳列。如果你對這個步驟不清楚, 你可以回顧一下本系列的第一篇。
參考:
- [入門] Chrome Extension 入門 #1
- [入門] Chrome Extension 入門 #2
- [入門] Chrome Extension 入門 #3
- [入門] Chrome Extension 入門 #4
- [入門] Chrome Extension 入門 #5
- [入門] Chrome Extension 入門 #6
- Manifest V3 migration checklist