브라우저 확장을 사용하고있을 수 있습니다. 광고 차단제, 비밀번호 관리자 및 PDF 시청자와 같이 일부 확장은 매우 인기 있고 유용합니다. 이러한 확장 (또는 "부가 기능")은 이것으로 제한되지 않습니다. 더 많은 일을 할 수 있습니다! 이 기사는 확장을 만드는 방법을 설명합니다. 결국, 우리는 그것을 여러 브라우저로 실행하게 할 것입니다.
우리는 "Reddit Transcription" 이라는 확장을 만들어 주석 섹션의 맨 위에 특정 주석을 이동하고 화면 리더에 Aria- 속성을 추가함으로써 Reddit 접근성을 향상시킬 것입니다. 또한 더 나은 텍스트 대비를위한 주석에 경계와 배경을 추가하는 옵션을 추가하여 확장을 한 단계 더 발전시킬 것입니다.
전체 아이디어는 브라우저 확장을 개발하는 방법에 대한 좋은 아이디어를 제공하는 것입니다. 먼저 Google Chrome, Microsoft Edge, Brave 등과 같은 크롬 기반 브라우저에 대한 확장자를 생성합니다. 향후 기사에서는 Firefox와 호환되도록 확장자를 포팅하고 최근 MACOS 및 iOS 버전의 브라우저에서 웹 확장자 지원을위한 Safari를 추가 할 것입니다.
GitHub 코드베이스가 준비 되었습니까? 단계별로 해보자.
먼저 프로젝트 작업 공간이 필요합니다. 우리가 정말로 필요한 것은 폴더를 만들고 이름을 지정하는 것입니다 (나는 그것을 트랜지스터 오피-오브 레딧이라고합니다). 그런 다음 소스 코드를 위해 SRC라는 폴더를 만듭니다.
진입 점은 확장자에 대한 일반 정보 (예 : 확장 이름, 설명 등)를 포함하는 파일이며 실행할 권한 또는 스크립트를 정의합니다.
우리의 진입 점은 방금 만든 SRC 폴더에 위치한 Manifest.json 파일 일 수 있습니다. 그것에 다음 세 가지 속성을 추가해 봅시다.
<code>{ "manifest_version": 3, "name": "Reddit 转录器", "version": "1.0" }</code>
Manifest_version은 NPM 또는 노드의 버전과 유사합니다. 사용 가능한 API를 정의합니다 (또는 사용 가능한 경우). 최첨단 작업을 위해 최신 버전 3 (MV3)을 사용할 것입니다.
두 번째 속성은 이름이며 확장자 이름을 지정합니다. 이 이름은 Chrome Web Store 및 Chrome Browser의 Chrome : // Extensions 페이지와 같이 모든 곳에 나타날 때 우리의 확장자가 나타나는 이름입니다.
그런 다음 버전이 있습니다. 확장자가 버전 번호로 표시됩니다. 이 속성 (Manifest_version과 반대로)은 숫자와 점 만 포함 할 수있는 문자열입니다 (예 : 1.3.5).
실제로, 우리는 확장의 컨텍스트를 추가하는 데 도움이되도록 더 추가 할 수 있습니다. 예를 들어, 확장 기능의 기능을 설명하는 설명을 제공 할 수 있습니다. 이 정보를 제공하는 것이 가장 좋습니다. 사용자에게 확장자를 사용할 때 직면 할 내용을 더 잘 이해할 수있게 되므로이 정보를 제공하는 것이 가장 좋습니다.
이 예에서는 설명을 추가 할뿐만 아니라 Chrome 웹 스토어가 확장 페이지를 가리키는 아이콘과 URL도 제공합니다.
<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>
확장의 가장 큰 장점 중 하나는 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>
이 연장을 방금 부여한 권한은 무엇입니까? 우선, 저장. 우리는이 확장자가 사용자의 설정을 저장하기 위해 브라우저의 웹 스토리지에 액세스하려면 저장해야합니다. 예를 들어, 사용자가 댓글이 빨간색 테두리를 표시하려는 경우 다음에 설정을 다시 설정하는 대신 설정을 저장합니다.
또한 사용자가 현재 화면으로 이동하는 방법을 확인하기 위해 확장 권한을 부여합니다. Reddit은 단일 페이지 응용 프로그램 (SPA)이므로 페이지 새로 고침을 트리거하지 않습니다. Reddit은 게시물을 클릭 할 때만 게시물에 대한 주석을로드하기 때문에이 상호 작용을 "캡처"해야합니다. 그래서 우리는 WebNavigation을 활용하는 이유입니다.
Manifest.json에 새로운 항목을 추가해야하므로 나중에 페이지에서 실행 코드를 다룰 것입니다.
/설명 허용되는 권한에 따라 브라우저는 사용자에게 권한을 수락하라는 경고를 표시 할 수 있습니다. 그러나 특정 권한만이 이와 같으며 Chrome은 이러한 권한에 대한 개요를 잘 갖습니다.
브라우저 확장에는 국제화 된 (I18N) API가 내장되어 있습니다. 여러 언어로 번역을 관리 할 수 있습니다 (전체 목록). API를 사용하려면 Manifest.json 파일에서 번역 및 기본 언어를 정의해야합니다.
<code>"default_locale": "en"</code>
이것은 영어를 언어로 설정합니다. 브라우저가 지원되지 않는 다른 언어로 설정되면 확장자는 기본 로케일 (이 예에서)으로 돌아갑니다.
우리의 번역은 _locales 디렉토리에 정의되어 있습니다. 지원할 각 언어에 대한 폴더를 만들어 봅시다. 각 하위 디렉토리에는 자체 메시지가 있습니다 .JSON 파일.
<code>src └─ _locales └─ en └─ messages.json └─ fr └─ messages.json</code>
번역 파일에는 여러 부분이 포함되어 있습니다.
다음은이 모든 것을 함께 제공하는 예입니다.
<code>{ "userGreeting": { // 翻译键(“id”) "message": "Good $daytime$, $user$!" // 翻译"description": "用户问候", // 翻译人员的可选描述"placeholders": { // 可选占位符"daytime": { // 如消息中所引用"content": "$1", "example": "morning" // 我们内容的示例值}, "user": { "content": "$1", "example": "Lars" } } } }</code>
자리 표시자를 사용하는 것은 약간 어렵습니다. 먼저 메시지에서 자리 표시자를 정의해야합니다. 자리 표시자는 $ 문자로 동봉해야합니다. 그 후, 우리는 자리 표시자를 "자리 표시 자 목록"에 추가해야합니다. 이것은 약간 직관적이지 않지만 Chrome은 자리 표시 자들에게 어떤 가치가 삽입되어야하는지 알고 싶어합니다. 우리는 여기에서 동적 값을 사용하기를 원하므로 삽입 한 값을 참조하기 위해 특별한 컨텐츠 값 $ 1을 사용합니다.
예제 속성은 선택 사항입니다. 번역가에게 자리 표시자가 할 수있는 것을 자극하는 데 사용될 수 있습니다 (그러나 실제로는 표시되지 않습니다).
우리는 확장에 대한 다음 번역을 정의해야합니다. Messages.json 파일에 복사하여 붙여 넣습니다. 더 많은 언어를 추가하십시오 (예 : 독일어를 사용하는 경우 _locales에 폴더를 추가하십시오).
<code>{ "name": { "message": "Reddit 转录器" }, "description": { "message": "子reddits 的辅助图像描述。" }, "popupManageSettings": { "message": "管理设置" }, "optionsPageTitle": { "message": "设置" }, "sectionGeneral": { "message": "常规设置" }, "settingBorder": { "message": "显示评论边框" }, "settingBackground": { "message": "显示评论背景" } }</code>
I18N 권한없이 왜 등록했는지 궁금 할 것입니다. 모든 권한을 등록 할 필요가 없기 때문에 크롬은 이와 관련하여 약간 이상합니다. 일부 (Chrome.i18n)는 Manifest에 등록 할 필요가 없습니다. 다른 권한에는 항목이 필요하지만 확장자가 설치되면 사용자에게 표시되지 않습니다. 다른 일부 권한은 "혼합"(예 : Chrome.runtime)이며, 이는 일부 기능을 권한을 선언하지 않고 사용할 수 있음을 의미하지만 동일한 API의 다른 기능에는 매니페스트에 등록 된 항목이 필요합니다. 이러한 차이점을 완전히 이해하려면 문서를 살펴 봐야합니다.
최종 사용자가 가장 먼저 보는 것은 Chrome 웹 스토어의 항목 또는 확장 개요 페이지입니다. 모든 것이 번역되도록 매니페스트 파일을 조정해야합니다.
<code>{ // 更新这些条目"name": "__MSG_name__", "description": "__MSG_description__" }</code>
이 구문을 적용하면 메시지에 해당 변환이 사용됩니다. json 파일 (예 : _msg 이름은 이름을 사용하여 번역됩니다).
HTML 파일에 번역을 적용하려면 일부 JavaScript가 필요합니다.
<code>chrome.i18n.getMessage('name');</code>
이 코드는 우리가 정의한 번역 (즉, Reddit Transcript)을 반환합니다. 자리 표시자는 비슷한 방식으로 수행 할 수 있습니다.
<code>chrome.i18n.getMessage('userGreeting', { daytime: 'morning', user: 'Lars' });</code>
이런 식으로 모든 요소에 번역을 적용하는 것은 번거 롭을 수 있습니다. 그러나 데이터 속성에 따라 번역을 수행하는 작은 스크립트를 쓸 수 있습니다. 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>
실제 프로그래밍을 시작하기 전에 두 페이지를 만들어야합니다.
다음은 페이지를 작성하는 데 필요한 폴더 및 파일에 대한 개요입니다.
<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 요소의 너비 및 높이 특성을 설정할 수 있습니다.
이것은 CSS 및 JavaScript 파일을 연결하는 HTML 골격입니다.
제목과 버튼을 추가하십시오. ```
<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 = getElementById ( 'title');
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>
"액션": { "default_popup": "popup/popup.html", "default_icon": { "16": "이미지/로고/16.png", "48": "이미지/로고/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, backgring : false,});
<code>接下来,我们需要加载保存的设置。我们可以为此使用(先前注册的)存储API。具体来说,我们需要定义是要在本地存储数据(chrome.storage.local) 还是通过登录的所有设备同步设置(chrome.storage.sync)。让我们在这个项目中使用本地存储。需要使用get 方法检索值。它接受两个参数: 1. 我们要加载的条目2. 包含值的回调我们的条目可以是字符串(例如,下面的settings)或条目数组(如果我们想要加载多个条目,则很有用)。回调函数中的参数包含我们先前在{ settings: ... } 中定义的所有条目的对象:</code>
chrome.storage.local.get ( 'settings', ({settings}) => {const 옵션 = 설정? defaultsettings; defaultsettings; // 설정이 정의되지 않으면 (! settings) {chrome.storage.local.set ({settings : defaultsettings,});
// 생성 및 디스플레이 옵션 const generalOptions = object.keys (옵션) .filter (x =>! x.startSwith ( 'advanced'));
generalOptions.foreach (옵션 => CreateOption (옵션, 옵션, grenalsection));
<code>为了呈现选项,我们还需要创建一个createOption() 函数。</code>
함수 createOption (setting, settingsobject, 래퍼) {const settingWrapper = <div><label for="${setting}">${chrome.i18n.getMessage(</label></div>
"div");
`;;
const toggleswitch = settingwrapper.querySelector ( "label.is-switch");
input.onchange = () => {toggleswitch.setAttribute ( 'aria-Checked', intupateSetting (setting, input.checked);
Toggleswitch.onkeydown = e => {if (e.key === ""|| e.key === "e.preventDefault ();
래퍼 .AppendChild (SettingWrapper);
<code>在我们的开关(又名单选按钮)的onchange 事件侦听器中,我们调用函数updateSetting。此方法将把单选按钮的更新值写入存储中。为此,我们将使用set 函数。它有两个参数:我们要覆盖的条目和(可选)回调(在本例中我们不使用)。由于我们的settings 条目不是布尔值或字符串,而是一个包含不同设置的对象,因此我们使用扩展运算符(...) 并仅覆盖settings 对象中的实际键(setting)。</code>
함수 updateSetting (key, value) {chrome.storage.local.get ( 'settings', ({settings}) => {chrome.storage.local.set ({settings : {... settings,
<code> } })</code>
});
<code>同样,我们需要通过将以下条目附加到manifest.json 来“通知”扩展程序我们的选项页面:</code>
"옵션 _ui": { "Open_In_Tab": true, "page": "옵션/옵션 .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);
<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 transmitter for Reddit') : false, torCommentsExist: () => !!document.querySelector(Selectors.torComment), commentWrapperExists: () => !! document.querySelector ( '[data-reddit-comment-wrapper = "true"]});
<code>接下来,我们检查用户是否直接打开评论页面(“帖子”),然后执行RegEx 检查并更新directPage 变量。当用户直接打开URL(例如,通过将其键入地址栏或单击另一个页面上的<a> 元素(例如Twitter))时,就会发生这种情况。</a></code>
directpage = false (urlregex.commentpage.test) {directpage = true};
<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 rapper ${Selectors.commentWrapper} > div
queperselector (selectors.commentwrapper);
rapper.dataset.redditcommentWrapper = 'true'; flexDirection = 'column';
if (directPage) {comment.querySelectorall ( "[data-reddit-comment-wrapper = 'true']);
chrome.storage.local.get ( 'settings', ({settings}) => {// 18 댓글을 강조 표시합니다 der) {comment.style.outline = '2px solid red'; COMMENT.STYL.ORDER = "-1";
<code>applyWaiAria() 函数在moveComments() 函数中调用——它添加aria- 属性。另一个函数创建唯一标识符以与aria- 属性一起使用。</code>
함수 applyWaiaria (postcontent, comment) {const postmedia = postcontent.querySelector ( 'class*= "imageBox-Image", video');
if (! postmedia) {return}
댓글.
function uuidv4() { return 'xxxxxxx-xxxx-4xxx-yxxxx-xxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); }
<code>以下函数等待评论加载,如果找到评论包装器,则调用回调参数。</code>
함수 waitforcomment (Callback) {const config = {childrist : true, subtree : true}; const observer = new mutationobserver (for (const mutation of mutation) {if (document.queryselector (selectors.commentWrapper)) {Callback (); clarever.)
Observer.Observe (document.documentElement, config);
함수 startObservingTimeout (옵저버, 초) {return settimeout (() => {inserver.DiscOntect (), 1000 * 초);
<code>### 添加服务工作者还记得我们在内容脚本中添加了消息侦听器吗?此侦听器当前未接收消息。我们需要自己将其发送到内容脚本。为此,我们需要注册一个服务工作者。我们必须通过将以下代码附加到manifest.json 来注册服务工作者:</code>
"배경": { "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; {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}] = chrome.tabs.query ({active : true, currentwindow : true});
chrome.tabs.sendMessage (tabid, {type : utils.getPageType (url));
<code>### 全部完成!我们完成了!导航到Chrome 的扩展程序管理页面(chrome://extensions),然后点击解压扩展程序上的重新加载图标。如果您打开包含“Reddit 转录器”评论和图像转录的Reddit 帖子(例如此帖子),只要我们在扩展程序设置中启用了它,它就会被移动到评论部分的开头并突出显示。 ### 结论这是否像您想象的那么难?在我深入研究之前,它肯定比我想象的要简单得多。在设置manifest.json 并创建任何我们需要的文件和资产后,我们真正做的只是像往常一样编写HTML、CSS 和JavaScript。如果您在途中遇到任何问题,Chrome API 文档是一个很好的资源,可以帮助您重回正轨。再次声明,这是包含我们在本文中介绍的所有代码的GitHub 代码库。阅读它,使用它,并让我知道您的想法!</code>
위 내용은 브라우저 확장을 만드는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!