搜尋
首頁web前端css教學如何創建瀏覽器擴展程序

How to Create a Browser Extension

您可能正在使用瀏覽器擴展程序。一些擴展程序非常流行且實用,例如廣告攔截器、密碼管理器和PDF 查看器。這些擴展程序(或“附加組件”)的功能並非僅限於此——您可以用它們做更多的事情!本文將向您介紹如何創建一個擴展程序。最終,我們將使其在多個瀏覽器中運行。

我們要製作什麼

我們將製作一個名為“Reddit 轉錄器”的擴展程序,它將通過將特定評論移動到評論部分的頂部並為屏幕閱讀器添加aria- 屬性來提高Reddit 的可訪問性。我們還將通過添加選項來為評論添加邊框和背景以獲得更好的文本對比度,從而使我們的擴展程序更進一步。

整個想法是讓您很好地了解如何開發瀏覽器擴展程序。我們將首先為基於Chromium 的瀏覽器(例如Google Chrome、Microsoft Edge、Brave 等)創建擴展程序。在未來的文章中,我們將移植該擴展程序以使其與Firefox 兼容,以及最近在其MacOS 和iOS 版本的瀏覽器中都添加了對Web Extensions 支持的Safari。

GitHub 代碼庫準備好了嗎?讓我們一步一步來。

創建工作目錄

首先,我們需要一個項目的工作空間。我們真正需要的只是創建一個文件夾並為其命名(我將其命名為transcribers-of-reddit)。然後,在其中創建一個名為src 的文件夾用於我們的源代碼。

定義入口點

入口點是一個包含有關擴展程序的常規信息(即擴展程序名稱、描述等)並定義要執行的權限或腳本的文件。

我們的入口點可以是位於我們剛剛創建的src 文件夾中的manifest.json 文件。在其中,讓我們添加以下三個屬性:

 <code>{ "manifest_version": 3, "name": "Reddit 转录器", "version": "1.0" }</code>

manifest_version 類似於npm 或Node 中的版本。它定義了哪些API 可用(或不可用)。我們將使用最新的版本3(也稱為mv3)進行前沿工作。

第二個屬性是name,它指定我們的擴展程序名稱。此名稱是我們的擴展程序出現在所有地方時顯示的名稱,例如Chrome 網上應用店和Chrome 瀏覽器中的chrome://extensions 頁面。

然後是version。它使用版本號標記擴展程序。請記住,此屬性(與manifest_version 相反)是一個字符串,只能包含數字和點(例如1.3.5)。

更多manifest.json 信息

實際上,我們可以添加更多內容來幫助添加擴展程序的上下文。例如,我們可以提供一個描述來解釋擴展程序的功能。最好提供這些信息,因為它可以讓用戶更好地了解他們在使用擴展程序時會遇到什麼。

在本例中,我們不僅添加了描述,還提供了Chrome 網上應用店在其擴展程序頁面上指向的圖標和網址。

 <code>{ "description": "使Reddit 对残疾用户更易于访问。", "icons": { "16": "images/logo/16.png", "48": "images/logo/48.png", "128": "images/logo/128.png" }, "homepage_url": "https://www.php.cn/link/530ebdeb0491c0459e00298fcdb3a2bd/extensions/tor/" }</code>
  • 描述顯示在Chrome 的管理頁面(chrome://extensions) 上,應簡短,少於132 個字符。
  • 圖標在很多地方都被使用。正如文檔中所述,最好提供三種不同分辨率的相同圖標版本,最好是PNG 文件。您可以隨意使用此示例的GitHub 代碼庫中的圖標。
  • homepage_url 可用於將您的網站與擴展程序連接起來。單擊管理頁面上的“更多詳細信息”時,將顯示包含鏈接的按鈕。

設置權限

擴展程序的一大優勢是它們的API 允許您直接與瀏覽器交互。但是我們必須明確地授予擴展程序這些權限,這也包含在manifest.json 文件中。

 <code>{ "manifest_version": 3, "name": "Reddit 转录器", "version": "1.0", "description": "使Reddit 对残疾用户更易于访问。", "icons": { "16": "images/logo/16.png", "48": "images/logo/48.png", "128": "images/logo/128.png" }, "homepage_url": "https://www.php.cn/link/530ebdeb0491c0459e00298fcdb3a2bd/extensions/tor/", "permissions": [ "storage", "webNavigation" ] }</code>

我們剛剛授予此擴展程序什麼權限?首先是storage。我們希望此擴展程序能夠保存用戶的設置,因此我們需要訪問瀏覽器的Web 存儲來保存它們。例如,如果用戶希望評論顯示紅色邊框,那麼我們將保存該設置以備下次使用,而不是讓他們再次設置。

我們還授予擴展程序查看用戶如何導航到當前屏幕的權限。 Reddit 是一個單頁應用程序(SPA),這意味著它不會觸發頁面刷新。我們需要“捕獲”此交互,因為只有在我們單擊帖子時,Reddit 才會加載帖子的評論。因此,這就是我們利用webNavigation 的原因。

我們稍後將介紹在頁面上執行代碼,因為它需要在manifest.json 中添加一個全新的條目。

/解釋根據允許的權限,瀏覽器可能會向用戶顯示警告以接受權限。但是,只有某些權限是這樣,Chrome 對這些權限有很好的概述。

管理翻譯

瀏覽器擴展程序具有內置的國際化(i18n) API。它允許您管理多種語言的翻譯(完整列表)。要使用API,我們必須在manifest.json 文件中定義我們的翻譯和默認語言:

 <code>"default_locale": "en"</code>

這將英語設置為語言。如果瀏覽器的設置為任何不受支持的其他語言,則擴展程序將回退到默認語言環境(在此示例中為en)。

我們的翻譯在_locales 目錄中定義。讓我們在其中為每種要支持的語言創建一個文件夾。每個子目錄都有自己的messages.json 文件。

 <code>src └─ _locales └─ en └─ messages.json └─ fr └─ messages.json</code>

翻譯文件包含多個部分:

  • 翻譯鍵(“id”):此鍵用於引用翻譯。
  • 消息:實際的翻譯內容
  • 描述(可選):描述翻譯(我不建議使用它們,它們只會使文件膨脹,並且您的翻譯鍵應該足夠具有描述性)
  • 佔位符(可選):可用於在翻譯中插入動態內容

這是一個將所有這些整合在一起的示例:

 <code>{ "userGreeting": { // 翻译键(“id”) "message": "Good $daytime$, $user$!" // 翻译"description": "用户问候", // 翻译人员的可选描述"placeholders": { // 可选占位符"daytime": { // 如消息中所引用"content": "$1", "example": "morning" // 我们内容的示例值}, "user": { "content": "$1", "example": "Lars" } } } }</code>

使用佔位符有點困難。首先,我們需要在消息中定義佔位符。佔位符需要用$ 字符括起來。之後,我們必須將佔位符添加到“佔位符列表”。這有點不直觀,但Chrome 希望知道應該為我們的佔位符插入什麼值。我們(顯然)希望在這裡使用動態值,因此我們使用特殊的content 值$1 來引用我們插入的值。

example 屬性是可選的。它可用於向翻譯人員提示佔位符可能是什麼值(但實際上並未顯示)。

我們需要為我們的擴展程序定義以下翻譯。將它們複製並粘貼到messages.json 文件中。隨意添加更多語言(例如,如果您說德語,請在_locales 中添加一個de 文件夾,依此類推)。

 <code>{ "name": { "message": "Reddit 转录器" }, "description": { "message": "子reddits 的辅助图像描述。" }, "popupManageSettings": { "message": "管理设置" }, "optionsPageTitle": { "message": "设置" }, "sectionGeneral": { "message": "常规设置" }, "settingBorder": { "message": "显示评论边框" }, "settingBackground": { "message": "显示评论背景" } }</code>

您可能想知道為什麼我們在沒有i18n 權限的情況下註冊了權限,對吧? Chrome 在這方面有點奇怪,因為您不需要註冊每個權限。有些(例如chrome.i18n)不需要在manifest 中註冊。其他權限需要一個條目,但在安裝擴展程序時不會顯示給用戶。其他一些權限是“混合”的(例如chrome.runtime),這意味著它們的一些功能可以在不聲明權限的情況下使用——但同一API 的其他功能需要在manifest 中註冊一個條目。您需要查看文檔以全面了解這些差異。

在manifest 中使用翻譯

最終用戶首先看到的是Chrome 網上應用店中的條目或擴展程序概述頁面。我們需要調整manifest 文件以確保所有內容都已翻譯。

 <code>{ // 更新这些条目"name": "__MSG_name__", "description": "__MSG_description__" }</code>

應用此語法將使用messages.json 文件中的相應翻譯(例如,_MSG name使用name 翻譯)。

在HTML 頁面中使用翻譯

在HTML 文件中應用翻譯需要一些JavaScript。

 <code>chrome.i18n.getMessage('name');</code>

該代碼返回我們定義的翻譯(即Reddit 轉錄器)。佔位符也可以類似的方式完成。

 <code>chrome.i18n.getMessage('userGreeting', { daytime: 'morning', user: 'Lars' });</code>

以這種方式將翻譯應用於所有元素會很麻煩。但是我們可以編寫一個小的腳本,根據data- 屬性執行翻譯。因此,讓我們在src 目錄中創建一個新的js 文件夾,然後在其中添加一個新的util.js 文件。

 <code>src └─ js └─ util.js</code>

這可以完成任務:

 <code>const i18n = document.querySelectorAll("[data-intl]"); i18n.forEach(msg => { msg.innerHTML = chrome.i18n.getMessage(msg.dataset.intl); }); chrome.i18n.getAcceptLanguages(languages => { document.documentElement.lang = languages[0]; });</code>

將此腳本添加到HTML 頁面後,我們可以向元素添加data-intl 屬性來設置其內容。文檔語言也將根據用戶語言設置。

<code>



</code>
<code>管理设置</code>

添加彈出窗口和選項頁面

在我們深入實際編程之前,我們需要創建兩個頁面:

  1. 包含用戶設置的選項頁面
  2. 當與地址欄旁邊的擴展程序圖標交互時打開的彈出窗口頁面。此頁面可用於各種場景(例如,用於顯示統計信息或快速設置)。

以下是我們需要創建頁面所需的文件夾和文件的概述:

 <code>src ├─ css | └─ paintBucket.css ├─ popup | ├─ popup.html | ├─ popup.css | └─ popup.js └─ options ├─ options.html ├─ options.css └─ options.js</code>

.css 文件包含純CSS,僅此而已。我不會詳細介紹,因為我知道你們大多數讀者已經完全了解CSS 的工作原理。您可以從該項目的GitHub 代碼庫中復制和粘貼樣式。

請注意,彈出窗口不是選項卡,其大小取決於其中的內容。如果您想使用固定大小的彈出窗口,可以在html 元素上設置width 和height 屬性。

創建彈出窗口

這是一個HTML 骨架,它鏈接CSS 和JavaScript 文件,並在

中添加標題和按鈕。 ```

 <code><meta charset="UTF-8">
<meta content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" name="viewport">
<meta content="ie=edge" http-equiv="X-UA-Compatible"></code> <title data-intl="name"></title><link href="../css/paintBucket.css" rel="stylesheet"><link href="popup.css" rel="stylesheet"><h1></h1>
 <code>h1 包含扩展程序名称和版本;按钮用于打开选项页面。标题将不会填充翻译(因为它缺少data-intl 属性),并且按钮还没有任何点击处理程序,因此我们需要填充popup.js 文件:</code>

const title = document.getElementById('title'); const settingsBtn = document.querySelector('button'); const manifest = chrome.runtime.getManifest();

title.textContent = ${manifest.name} (${manifest.version}) ;

settingsBtn.addEventListener('click', () => { chrome.runtime.openOptionsPage(); });

<code>此脚本首先查找manifest 文件。Chrome 提供了包含getManifest 方法的runtime API(此特定方法不需要runtime 权限)。它将我们的manifest.json 返回为JSON 对象。在我们使用扩展程序名称和版本填充标题后,我们可以向设置按钮添加事件侦听器。如果用户与之交互,我们将使用chrome.runtime.openOptionsPage() 打开选项页面(同样不需要权限条目)。弹出窗口页面现在已完成,但扩展程序尚不知道它的存在。我们必须通过将以下属性附加到manifest.json 文件来注册弹出窗口。</code>

"action": { "default_popup": "popup/popup.html", "default_icon": { "16": "images/logo/16.png", "48": "images/logo/48.png", "128": "images/logo/128.png" } },

 <code>#### 创建选项页面创建此页面的过程与我们刚刚完成的过程非常相似。首先,我们填充options.html 文件。以下是一些我们可以使用的标记:</code> 

<circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>

<code><div></div></code>
<p>由<a href="https://www.php.cn/link/530ebdeb0491c0459e00298fcdb3a2bd" target="_blank">lars.koelker.dev</a>提供的Reddit 轉錄器擴展程序。</p>

Reddit 是Reddit, Inc. 的註冊商標。此擴展程序未以任何方式獲得Reddit, Inc. 的認可或關聯。

<code>目前还没有实际的选项(只有它们的包装器)。我们需要编写选项页面的脚本。首先,我们在options.js 中定义变量以访问我们的包装器和默认设置。“冻结”我们的默认设置可以防止我们以后意外修改它们。</code>

const defaultSettings = Object.freeze({ border: false, background: false, }); const generalSection = document.getElementById('generalOptionsWrapper');

<code>接下来,我们需要加载保存的设置。我们可以为此使用(先前注册的)存储API。具体来说,我们需要定义是要在本地存储数据(chrome.storage.local) 还是通过登录的所有设备同步设置(chrome.storage.sync)。让我们在这个项目中使用本地存储。需要使用get 方法检索值。它接受两个参数: 1. 我们要加载的条目2. 包含值的回调我们的条目可以是字符串(例如,下面的settings)或条目数组(如果我们想要加载多个条目,则很有用)。回调函数中的参数包含我们先前在{ settings: ... } 中定义的所有条目的对象:</code>

chrome.storage.local.get('settings', ({ settings }) => { const options = settings ?? defaultSettings; // 如果未定義設置,則回退到默認設置if (!settings) { chrome.storage.local.set({ settings: defaultSettings, }); }

// 創建和顯示選項const generalOptions = Object.keys(options).filter(x => !x.startsWith('advanced'));

generalOptions.forEach(option => createOption(option, options, generalSection)); });

<code>为了呈现选项,我们还需要创建一个createOption() 函数。</code>

function createOption(setting, settingsObject, wrapper) { const settingWrapper = document.createElement("div"); settingWrapper.classList.add("setting-item"); settingWrapper.innerHTML = <div><label for="${setting}">${chrome.i18n.getMessage(</label></div> setting${setting}`)}

`;

const toggleSwitch = settingWrapper.querySelector("label.is-switch"); const input = settingWrapper.querySelector("input");

input.onchange = () => { toggleSwitch.setAttribute('aria-checked', input.checked); updateSetting(setting, input.checked); };

toggleSwitch.onkeydown = e => { if(e.key === " " || e.key === "Enter") { e.preventDefault(); toggleSwitch.click(); } }

wrapper.appendChild(settingWrapper); }

<code>在我们的开关(又名单选按钮)的onchange 事件侦听器中,我们调用函数updateSetting。此方法将把单选按钮的更新值写入存储中。为此,我们将使用set 函数。它有两个参数:我们要覆盖的条目和(可选)回调(在本例中我们不使用)。由于我们的settings 条目不是布尔值或字符串,而是一个包含不同设置的对象,因此我们使用扩展运算符(...) 并仅覆盖settings 对象中的实际键(setting)。</code>

function updateSetting(key, value) { chrome.storage.local.get('settings', ({ settings }) => { chrome.storage.local.set({ settings: { ...settings,

<code> } })</code>

}); }

<code>同样,我们需要通过将以下条目附加到manifest.json 来“通知”扩展程序我们的选项页面:</code>

"options_ui": { "open_in_tab": true, "page": "options/options.html" },

<code>根据您的用例,您还可以通过将open_in_tab 设置为false 来强制选项对话框作为弹出窗口打开。 ### 安装开发扩展程序现在我们已经成功设置了manifest 文件并将弹出窗口和选项页面都添加到了组合中,我们可以安装扩展程序来检查我们的页面是否正常工作。导航到chrome://extensions 并启用“开发者模式”。将出现三个按钮。单击标记为“加载解压”的按钮,然后选择扩展程序的src 文件夹以加载它。扩展程序现在应该已成功安装,并且我们的“Reddit 转录器”图块应该在页面上。我们现在已经可以与扩展程序交互了。单击地址栏旁边的拼图块(?) 图标,然后单击新添加的“Reddit 转录器”扩展程序。您现在应该会看到一个小的弹出窗口,其中包含一个按钮,用于打开选项页面。不错吧?在我的设备上它可能看起来有点不同,因为我在这些屏幕截图中启用了深色模式。如果您启用“显示评论背景”和“显示评论边框”设置,然后重新加载页面,则状态将保留,因为我们将其保存在浏览器的本地存储中。 ### 添加内容脚本好的,我们现在已经可以触发弹出窗口并与扩展程序设置交互,但是扩展程序本身还没有做任何特别有用的事情。为了让它发挥作用,我们将添加一个内容脚本。在js 目录中添加一个名为comment.js 的文件,并确保在manifest.json 文件中定义它:</code>

"content_scripts": [ { "matches": [ " ://www.reddit.com/ " ], "js": [ "js/comment.js" ] } ],

 <code>content_scripts 由两部分组成: - matches:此数组保存URL,这些URL 告诉浏览器我们希望内容脚本在何处运行。作为Reddit 的扩展程序,我们希望它在与://www.redit.com/* 匹配的任何页面上运行,其中星号是通配符,用于匹配顶级域之后的任何内容。 - js:此数组包含实际的内容脚本。内容脚本无法与其他(普通)JavaScript 交互。这意味着如果网站的脚本定义了变量或函数,我们就无法访问它。例如:</code>

// script_on_website.js const username = 'Lars';

// content_script.js console.log(username); // 錯誤:username 未定義

<code>现在让我们开始编写内容脚本。首先,我们在comment.js 中添加一些常量。这些常量包含稍后将使用的RegEx 表达式和选择器。CommentUtils 用于确定帖子是否包含“tor 评论”,或者是否存在评论包装器。</code>

const messageTypes = Object.freeze({ COMMENT_PAGE: 'comment_page', SUBREDDIT_PAGE: 'subreddit_page', MAIN_PAGE: 'main_page', OTHER_PAGE: 'other_page', });

const Selectors = Object.freeze({ commentWrapper: 'div[style ="--commentswrapper-gradient-color"] > div, div[style ="max-height: unset"] > div', torComment: 'div[data-tor-comment]', postContent: 'div[data-test-]' });

const UrlRegex = Object.freeze({ commentPage: /\/r\/. \/comments\/. /, subredditPage: /\/r\/.*\// });

const CommentUtils = Object.freeze({ isTorComment: (comment) => comment.querySelector('[data-test-]') ? comment.querySelector('[data-test-]').textContent.includes('ma human volunteer content transcriber for Reddit') : false, torCommentsExist: () => !!document.querySelector(Selectors.torComment), commentWrapperExists: () => !!document.querySelector('[data-reddit-comment-wrapper="true"]') });

<code>接下来,我们检查用户是否直接打开评论页面(“帖子”),然后执行RegEx 检查并更新directPage 变量。当用户直接打开URL(例如,通过将其键入地址栏或单击另一个页面上的<a> 元素(例如Twitter))时,就会发生这种情况。</a></code>

let directPage = false; if (UrlRegex.commentPage.test(window.location.href)) { directPage = true; moveComments(); }

<code>除了直接打开页面外,用户通常还会与SPA 交互。为了捕获这种情况,我们可以通过使用runtime API 向comment.js 文件添加消息侦听器。</code>

chrome.runtime.onMessage.addListener(msg => { if (msg.type === messageTypes.COMMENT_PAGE) { waitForComment(moveComments); } });

<code>我们现在只需要这些函数。让我们创建一个moveComments() 函数。它将特殊的“tor 评论”移动到评论部分的开头。它还会根据设置中是否启用了边框,有条件地将背景颜色和边框应用于评论。为此,我们调用存储API 并加载settings 条目:</code>

function moveComments() { if (CommentUtils.commentWrapperExists()) { return; }

const wrapper = document.querySelector(Selectors.commentWrapper); let comments = wrapper.querySelectorAll( ${Selectors.commentWrapper} > div ); const postContent = document.querySelector(Selectors.postContent);

wrapper.dataset.redditCommentWrapper = 'true'; wrapper.style.flexDirection = 'column'; wrapper.style.display = 'flex';

if (directPage) { comments = document.querySelectorAll("[data-reddit-comment-wrapper='true'] > div"); }

chrome.storage.local.get('settings', ({ settings }) => { // HIGHLIGHT 18 comments.forEach(comment => { if (CommentUtils.isTorComment(comment)) { comment.dataset.torComment = 'true'; if (settings.background) { comment.style.backgroundColor = 'var(--newCommunityTheme-buttonAlpha05)'; } if (settings.border) { comment.style.outline = '2px solid red'; } comment.style.order = "-1"; applyWaiAria(postContent, comment); } }); }) }

 <code>applyWaiAria() 函数在moveComments() 函数中调用——它添加aria- 属性。另一个函数创建唯一标识符以与aria- 属性一起使用。</code>

function applyWaiAria(postContent, comment) { const postMedia = postContent.querySelector('img[class*="ImageBox-image"], video'); const commentId = uuidv4();

if (!postMedia) { return; }

comment.setAttribute('id', commentId); postMedia.setAttribute('aria-describedby', commentId); }

function uuidv4() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); }

<code>以下函数等待评论加载,如果找到评论包装器,则调用回调参数。</code>

function waitForComment(callback) { const config = { childList: true, subtree: true }; const observer = new MutationObserver(mutations => { for (const mutation of mutations) { if (document.querySelector(Selectors.commentWrapper)) { callback(); observer.disconnect(); clearTimeout(timeout); break; } } });

observer.observe(document.documentElement, config); const timeout = startObservingTimeout(observer, 10); }

function startObservingTimeout(observer, seconds) { return setTimeout(() => { observer.disconnect(); }, 1000 * seconds); }

 <code>### 添加服务工作者还记得我们在内容脚本中添加了消息侦听器吗?此侦听器当前未接收消息。我们需要自己将其发送到内容脚本。为此,我们需要注册一个服务工作者。我们必须通过将以下代码附加到manifest.json 来注册服务工作者:</code>

"background": { "service_worker": "sw.js" }

<code>不要忘记在src 目录中创建sw.js 文件(服务工作者始终需要在扩展程序的根目录src 中创建)。现在,让我们为消息和页面类型创建一些常量:</code>

const messageTypes = Object.freeze({ COMMENT_PAGE: 'comment_page', SUBREDDIT_PAGE: 'subreddit_page', MAIN_PAGE: 'main_page', OTHER_PAGE: 'other_page', });

const UrlRegex = Object.freeze({ commentPage: /\/r\/. \/comments\/. /, subredditPage: /\/r\/.*\// });

const Utils = Object.freeze({ getPageType: (url) => { if (new URL(url).pathname === '/') { return messageTypes.MAIN_PAGE; } else if (UrlRegex.commentPage.test(url)) { return messageTypes.COMMENT_PAGE; } else if (UrlRegex.subredditPage.test(url)) { return messageTypes.SUBREDDIT_PAGE; }

 <code>return messageTypes.OTHER_PAGE;</code>

} });

<code>我们可以添加服务工作者的实际内容。我们使用历史状态上的事件侦听器(onHistoryStateUpdated) 来执行此操作,该侦听器检测何时使用History API 更新页面(通常在SPA 中用于在没有页面刷新情况下导航)。在此侦听器中,我们查询活动选项卡并提取其tabId。然后,我们将包含页面类型和URL 的消息发送到我们的内容脚本。</code>

chrome.webNavigation.onHistoryStateUpdated.addListener(async ({ url }) => { const [{ id: tabId }] = await chrome.tabs.query({ active: true, currentWindow: true });

chrome.tabs.sendMessage(tabId, { type: Utils.getPageType(url), url }); });

 <code>### 全部完成!我们完成了!导航到Chrome 的扩展程序管理页面(chrome://extensions),然后点击解压扩展程序上的重新加载图标。如果您打开包含“Reddit 转录器”评论和图像转录的Reddit 帖子(例如此帖子),只要我们在扩展程序设置中启用了它,它就会被移动到评论部分的开头并突出显示。 ### 结论这是否像您想象的那么难?在我深入研究之前,它肯定比我想象的要简单得多。在设置manifest.json 并创建任何我们需要的文件和资产后,我们真正做的只是像往常一样编写HTML、CSS 和JavaScript。如果您在途中遇到任何问题,Chrome API 文档是一个很好的资源,可以帮助您重回正轨。再次声明,这是包含我们在本文中介绍的所有代码的GitHub 代码库。阅读它,使用它,并让我知道您的想法!</code>

以上是如何創建瀏覽器擴展程序的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
什麼是CSS網格?什麼是CSS網格?Apr 30, 2025 pm 03:21 PM

CSS網格是創建複雜,響應式Web佈局的強大工具。它簡化了設計,提高可訪問性並提供了比舊方法更多的控制權。

什麼是CSS Flexbox?什麼是CSS Flexbox?Apr 30, 2025 pm 03:20 PM

文章討論了CSS FlexBox,這是一種佈局方法,用於有效地對齊和分佈響應設計中的空間。它說明了FlexBox用法,將其與CSS網格進行了比較,並詳細瀏覽了瀏覽器支持。

我們如何使用CSS使網站迅速響應?我們如何使用CSS使網站迅速響應?Apr 30, 2025 pm 03:19 PM

本文討論了使用CSS創建響應網站的技術,包括視口元標籤,靈活的網格,流體媒體,媒體查詢和相對單元。它還涵蓋了使用CSS網格和Flexbox一起使用,並推薦CSS框架

CSS盒裝屬性有什麼作用?CSS盒裝屬性有什麼作用?Apr 30, 2025 pm 03:18 PM

本文討論了CSS盒裝屬性,該屬性控制了元素維度的計算方式。它解釋了諸如Content-Box,Border-Box和Padding-Box之類的值,以及它們對佈局設計和形式對齊的影響。

我們如何使用CSS動畫?我們如何使用CSS動畫?Apr 30, 2025 pm 03:17 PM

文章討論使用CSS,關鍵屬性並與JavaScript結合創建動畫。主要問題是瀏覽器兼容性。

我們可以使用CSS向我們的項目添加3D轉換嗎?我們可以使用CSS向我們的項目添加3D轉換嗎?Apr 30, 2025 pm 03:16 PM

文章討論了Web項目的3D轉換,關鍵屬性,瀏覽器兼容性和性能注意事項的討論。 (角色計數:159)

我們如何在CSS中添加梯度?我們如何在CSS中添加梯度?Apr 30, 2025 pm 03:15 PM

文章討論了使用CSS梯度(線性,徑向,重複)來增強網站視覺效果,添加深度,焦點和現代美學。

CSS中的偽元素是什麼?CSS中的偽元素是什麼?Apr 30, 2025 pm 03:14 PM

文章討論了CSS中的偽元素,它們在增強HTML樣式方面的使用以及與偽級的差異。提供實用的例子。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器