--- title: 你的第二個 WebExtension slug: Mozilla/Add-ons/WebExtensions/Your_second_WebExtension translation_of: Mozilla/Add-ons/WebExtensions/Your_second_WebExtension ---
{{AddonSidebar}}
假如你已經讀過了 你的第一個 WebExtension,你也已經知道該如何寫一個 extension(外掛),在這篇文章中我們將會教你寫一個稍微複雜一點的 extension,來 demo 一些 API 的使用。
在這個 extension 中,將會新增一個按鈕到 Firefox 的工具列上,當使用者按下按鈕後,將會顯示一個彈出視窗 (pop-up) 並可選擇一個動物。當使用者選擇了一個動物後,將會在當前的網頁中顯示使用者所選的動物圖片。
為了實作這個,我們將需要:
下面是這次 extension 的流程圖:
這個一個簡單的 extension,但是會教你許多基本的 WebExtensions API 的概念:
也可以在 GitHub 上找到範例的原始碼: https://github.com/mdn/webextensions-examples/tree/master/beastify
實作這個 extension 前,請先確認你的 Firefox 有 45.0 或更新的版本。
新增一個資料夾,然後進去:
mkdir beastify cd beastify
在資料夾 "beastify" 下新增一個檔案,並命名為 "manifest.json",然後撰寫以下程式碼。
{ "manifest_version": 2, "name": "Beastify", "version": "1.0", "description": "Adds a browser action icon to the toolbar. Click the button to choose a beast. The active tab's body content is then replaced with a picture of the chosen beast. See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Examples#beastify", "homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/beastify", "icons": { "48": "icons/beasts-48.png" }, "permissions": [ "activeTab" ], "browser_action": { "default_icon": "icons/beasts-32.png", "default_title": "Beastify", "default_popup": "popup/choose_beast.html" }, "web_accessible_resources": [ "beasts/frog.jpg", "beasts/turtle.jpg", "beasts/snake.jpg" ] }
manifest_version
、name
、version
必須寫進去,它包含了附加元件的基本詮釋資料(metadata)。description
和 homepage_url
為非必要但建議加上:主要在說明該 extension。icons
為非必要但建議加上:它允許附加元件指定圖示、也會在附加元件的管理員顯示permissions
列出了該 extension 所需要的權限。這邊我們只會要求 activeTab
permission 。browser_action
定義工具列的按鈕,在這邊我們將會提供三種 key:
default_icon
為必要的:告訴 button 該使用的 icon 為何default_title
為非必要的:該 value 會顯示在 button 的 tip 裡default_popup
如果想要顯示 pop-up,此為必要的 key:此教學中有使用到 pop-up 故為必要的,並將 HTML 檔案指給他。web_accessible_resources
列出所有希望讓網頁可以存取的檔案。所有的路徑都會關連到 manifest.json 。
一個 extension 應該要有一個 icon。icon 將會顯示在 Add-ons Manager 的 extension 列表中。(在 Firefox 網址列輸入 "about:addons" 開啟 Add-ons Manager)。
在 beastify 下建立一個名為 "icons" 的資料夾,並準備一個命名為 "beasts-48.png" 的 icon並存在 "beastify/icons" 的資料夾中(可以使用我們的範例圖檔,圖檔來源:Free Retina Icon Set,遵照使用條款來使用)。並在 manifest.json 裡告訴他要使用 "icons/beasts-48.png" 路徑下的 icon。
如果你想要使用自己的 icon,icon 大小必須是 48x48 pixels,另外也可使用 96x96 pixel 來支援較高解析度的顯示。
"icons": {
"48": "icons/beasts-48.png",
"96": "icons/beasts-96.png"
}
工具列按鈕也需要一個 icon,在 manifest.json 裡 "browser_action" 物件中的 "default_icon" 中告訴他要使用 "icons/beasts-32.png" 路徑下的 icon。。
準備一個命名為 "beasts-32.png" 的 icon,並存在 "beastify/icons" 資料夾中(你可以使用範例圖檔,圖檔來源:IconBeast Lite icon set,遵守使用條款來使用)。
假設你不使用 pop-up,當按下按鈕的時候就會觸發事件。假如使用 pop-up ,當按下按鈕時並不會觸發事件,取而代之會打開 pop-up。不過這邊我們想要用 pop-up,所以接來下會教你如何新增他。
pop-up 的方法主要是讓使用者可以選擇三個動物中的其中一個。
在 beastify 下 新增一個名為 "popup" 的資料夾,該資料夾中會包含以下三個檔案:
choose_beast.html
定義 pop-up 的顯示的內容文字choose_beast.css
定義 html 裡的 styles choose_beast.js
當使用者選擇動物後實行的腳本內容mkdir popup
cd popup
touch choose_beast.html choose_beast.css choose_beast.js
HTML 內容長得像這樣:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="choose_beast.css"/> </head> <body> <div id="popup-content"> <div class="button beast">Frog</div> <div class="button beast">Turtle</div> <div class="button beast">Snake</div> <div class="button reset">Reset</div> </div> <div id="error-content" class="hidden"> <p>Can't beastify this web page.</p><p>Try a different page.</p> </div> <script src="choose_beast.js"></script> </body> </html>
我們在 ID 為 "popup-content"
的 <div>
元件裡建立了一個包含每種動物選項的元件。當載入 popup 發生問題時,用另外一個 ID 為 "error-content"
且類別定義為 "hidden"
的 <div>
元件來處理。
值得注意的是我們在這個檔案裡引用了 CSS 與 JS 檔案,就如同一般網頁。
CSS 定義了 pop-up 的大小,並確保三個選項有填滿整個 pop-up,並給他們幾個基本的 style:
html, body { width: 100px; } .button { margin: 3% auto; padding: 4px; text-align: center; font-size: 1.5em; cursor: pointer; } .beast:hover { background-color: #CFF2F2; } .beast { background-color: #E5F2F2; } .clear { background-color: #FBFBC9; } .clear:hover { background-color: #EAEAC9; }
在 pop-up 的 JavaScript 中,我們監控著 click 事件。當按下其中一個選項後,將會讀取 js 檔到當前的瀏覽器分頁(active_tab)中,當內容腳本被讀取後,將會發送一個訊息告訴他該選擇哪一張圖片。
/* Given the name of a beast, get the URL to the corresponding image. */ function beastNameToURL(beastName) { switch (beastName) { case "Frog": return browser.extension.getURL("beasts/frog.jpg"); case "Snake": return browser.extension.getURL("beasts/snake.jpg"); case "Turtle": return browser.extension.getURL("beasts/turtle.jpg"); } } /* Listen for clicks in the popup. If the click is on one of the beasts: Inject the "beastify.js" content script in the active tab. Then get the active tab and send "beastify.js" a message containing the URL to the chosen beast's image. If it's on a button which contains class "clear": Reload the page. Close the popup. This is needed, as the content script malfunctions after page reloads. */ document.addEventListener("click", (e) => { if (e.target.classList.contains("beast")) { var chosenBeast = e.target.textContent; var chosenBeastURL = beastNameToURL(chosenBeast); browser.tabs.executeScript(null, { file: "/content_scripts/beastify.js" }); var gettingActiveTab = browser.tabs.query({active: true, currentWindow: true}); gettingActiveTab.then((tabs) => { browser.tabs.sendMessage(tabs[0].id, {beastURL: chosenBeastURL}); }); } else if (e.target.classList.contains("clear")) { browser.tabs.reload(); window.close(); } });
這邊使用了三個 WebExtensions API 的方法:
browser.tabs.executeScript
讀取內容腳本 "content_scripts/beastify.js" 到當前的瀏覽器分頁裡面browser.tabs.query
取得當前的瀏覽器分頁browser.tabs.sendMessage
送訊息到當前的瀏覽器分頁中正在執行的內容腳本裡(beastify.js)。訊息包含了所選的動物的 URL在 beastify 下建立一個名為 "content_scripts" 的資料夾,並新增一個命名為 "beastify.js" 的檔案,檔案裡的內容:
/* beastify(): * removes every node in the document.body, * then inserts the chosen beast * then removes itself as a listener */ function beastify(request, sender, sendResponse) { removeEverything(); insertBeast(request.beastURL); browser.runtime.onMessage.removeListener(beastify); } /* Remove every node under document.body */ function removeEverything() { while (document.body.firstChild) { document.body.firstChild.remove(); } } /* Given a URL to a beast image, create and style an IMG node pointing to that image, then insert the node into the document. */ function insertBeast(beastURL) { var beastImage = document.createElement("img"); beastImage.setAttribute("src", beastURL); beastImage.setAttribute("style", "width: 100vw"); beastImage.setAttribute("style", "height: 100vh"); document.body.appendChild(beastImage); } /* Assign beastify() as a listener for messages from the extension. */ browser.runtime.onMessage.addListener(beastify);
內容腳本中新增了一個 listener ,使其從 extension 可傳送訊息。(具體來說是從 "choose_beast.js" 這邊) ,在 listener 中做了:
document.body
中所有的 element ()<img>
element 並告訴它圖片的 URL,並插入到文件中最後,我們需要將動物的照片放進來
新增一個名為 "beasts" 的資料夾,並把三張動物的圖片放進此資料夾中,請取相對應的檔名。可以使用範例圖片 ,或從這邊下載:
首先,請再三的確認檔案有放到相對應的資料夾中:
beastify/ beasts/ frog.jpg snake.jpg turtle.jpg content_scripts/ beastify.js icons/ beasts-32.png beasts-48.png popup/ choose_beast.css choose_beast.html choose_beast.js manifest.json
開啟 Firefox 45.0,並安裝本地的 extensive 到瀏覽器裡。
在 Firefox 網址列輸入 "about:debugging" ,點選 "Load Temporary Add-on",然後選擇你的 "manifest.json" 檔案。然後應該就會看到 extensive 的 icon 出現在工具列上了:
{{EmbedYouTube("sAM78GU4P34")}}
打開一個網頁,點選 icon,選擇一個動物的名字,將會看到網頁內容被動物的圖片取代了:
{{EmbedYouTube("YMQXyAQSiE8")}}
你可以利用web-ext自動化暫時載入。
試試看:
cd beastify web-ext run