1
首发于公众号 大迁世界,欢迎关注。📝 每周7篇实用的前端文章 🛠️ 分享值得关注的开发工具 😜分享个人创业过程中的趣事

曾经想过制作自己的Chrome扩展,却因为觉得过程太复杂而打消了念头吗?
好消息,事情并没有你想象的那么复杂!在接下来的几分钟里,我们不仅将为你详解Chrome扩展的基础知识,还将手把手教你如何用五个简单的步骤创建自己的扩展。

我们将构建什么?

近年来,我们见证了人工智能能力的飞速发展。尽管这些全新的数字助手为我们带来了前所未有的便捷,但它们也随之带来了一个提醒:不要与它们分享敏感信息。

不知道你如何看待这一点,但对我来说,我的手指动作通常比我的大脑快。为了预防可能的失误,我们将为 ChatGPT 构建一个 “molly-guard”

如果你在疑惑什么是 “molly-guard”,它最初是用来指一个放在按钮或开关上的盾牌,以防止意外激活。在我们的上下文中,它是一个数字守护者,确保我们不会过度分享信息。

用户可以指定他们认为敏感的单词或短语列表。如果我们试图向ChatGPT提交包含这些词的信息,扩展将立即启动,禁用提交按钮,并防止我们可能的疏忽。

image.png

什么是Google Chrome扩展?

在我们开始之前,让我们先明确一下 Chrome 扩展到底是什么。Chrome 扩展是一小块旨在增强或修改 Chrome 浏览体验的软件。扩展是用标准的网络技术——HTML,JavaScript和CSS——开发的,它们可以从简单的工具(如颜色选择器)到更复杂的工具(如密码管理器)。

注:对于那些渴望更深入了解Chrome扩展的人,Google的官方文档是一份极其宝贵的资源。

值得注意的是,Google Chrome 扩展可以根据其预期的功能采取多种形式。有些有一个浏览器动作,通过地址栏旁边的图标可见,以便快速访问其功能。其他一些可能会在后台默默运行,在所有网页上或仅在特定网页上,具体取决于它们的设计。

对于我们的教程,我们将专注于使用内容脚本的扩展类型。该脚本将允许我们与特定页面的DOM进行交互和操作——在我们的情况下,即ChatGPT界面。

步骤1:创建扩展文件

首先,我们需要为我们的Chrome扩展设置基本结构。我们的扩展名为chatgpt-mollyguard,将在一个专门的文件夹中进行组织。这个扩展目录将包含所有必要的文件,以使我们的 molly-guard 能够顺畅运行。

下面是一个细分:

  • 文件夹chatgpt-molly-guard。这是我们扩展的根目录,所有我们的文件都将存放在这个文件夹里。
  • 文件:manifest.json。这是我们扩展的核心和灵魂,这个文件包含有关扩展的元数据,例如其名称、版本和所需的权限。最重要的是,它指定了在哪些网站上运行哪些脚本。
  • 文件:contentScript.js。顾名思义,这个JavaScript文件包含内容脚本。这个脚本可以直接访问网页的内容,允许我们扫描敏感词并根据需要修改页面。
  • 文件:wordsList.js。一个专门用于包含用户指定的敏感词或短语列表的JavaScript文件。我们将这个文件单独出来,以便用户可以轻松自定义他们的列表,而无需深入了解contentScript.js中的核心功能。
  • 文件:styles.css。一个样式表,用于为我们的扩展增加一些外观效果。虽然我们的主要目标是功能性,但使我们的警告或提示看起来更好也无妨!
  • 要开始:
  1. 在你的电脑上创建一个名为 chatgpt-molly-guard 的新文件夹。
  2. 在这个文件夹内,创建上面列出的四个文件。
  3. 有了这些文件,我们就准备好开始填写细节了。

image.png

在接下来的几节中,我们将更深入地探讨每个文件,并概述其在扩展中的特定作用。

步骤2:创建 Manifest 文件

Manifest 文件是一个 JSON 文件,它向浏览器提供了有关你的扩展的基本信息。这个文件必须位于扩展的根目录中。

以下是我们的 manifest 结构。将这段代码复制到 manifest.json

{
  "manifest_version": 3,
  "name": "ChatGPT Molly-guard",
  "version": "1.0",
  "description": "Prevents submission if specific words are typed into chat window",
  "content_scripts": [
    {
      "matches": ["https://chat.openai.com/*"],
      "css": ["styles.css"],
      "js": ["wordsList.js", "contentScript.js"]
    }
  ]
}

Manifest 文件有三个必填字段,分别是:manifest_versionnameversion。其他都是可选的。

主要 Manifest 元素

  • manifest_version:一个整数,指定 manifest 文件格式的版本。我们使用的是 Manifest V3,这是目前可用的最新版本。请注意,Google 正在积极淘汰 2023 年的 Manifest V2 扩展。
  • name:一个简短的纯文本字符串(最多 45 个字符),用于标识扩展。
  • version:一个到四个用点分隔的整数,用于标识扩展的版本。
  • description:一个纯文本字符串(不包含 HTML,最多 132 个字符),用于描述扩展。
  • content_scripts:此键静态地指定每次打开与 URL 模式(由 matches 键指定)匹配的页面时要使用的 JavaScript 或 CSS 文件。这里,我们说我们的脚本应该运行在以 https://chat.openai.com/ 开头的任何 URL 上。

在上述字段中,Google 将在 Chrome 的扩展管理页面和 Chrome 网上商店中显示你的扩展的名称、版本和描述。

尽管我们的 manifest 是针对我们的需求进行了精简,但还有许多其他字段可以为你的扩展添加深度和功能。例如 actiondefault_locale、icons 等字段提供了自定义选项、UI 控制和国际化支持。

要全面了解 manifest.json 文件中的可用内容,请参阅 Google 的官方文档

步骤3:创建 Content Script

Chrome 扩展中的 Content Script 是运行在网页上下文中的 JavaScript 文件。它们可以查看和操作正在运行的页面的 DOM,从而改变网页的内容和行为。

这是我们的内容脚本。将以下代码复制到 contentScript.js 文件中:

const debounce = (callback, wait) => {
  let timeoutId = null;
  return (...args) => {
    window.clearTimeout(timeoutId);
    timeoutId = window.setTimeout(() => {
      callback.apply(null, args);
    }, wait);
  };
};

function containsForbiddenWords(value) {
  return forbiddenWords.some(word => value.toLowerCase().includes(word.toLowerCase()));
}

function updateUI(target) {
  const containsForbiddenWord = containsForbiddenWords(target.value);
  const sendButton = target.nextElementSibling;
  const parentDiv = target.parentElement;

  if (containsForbiddenWord) {
    sendButton.disabled = true;
    parentDiv.classList.add('forbidden-div');
  } else {
    sendButton.disabled = false;
    parentDiv.classList.remove('forbidden-div');
  }
}

document.body.addEventListener('keyup', debounce((event) => {
  if (event.target.id === 'prompt-textarea') updateUI(event.target);
}, 300));

document.addEventListener('keydown', (e) => {
  if (e.target.id === 'prompt-textarea' && e.key === 'Enter') {
    if (containsForbiddenWords(e.target.value)) {
      e.stopPropagation();
      e.preventDefault();
    }
  }
}, true);

让我们一步一步来解析这个脚本。

文件的顶部声明了一个 debounce 函数。我们将使用这个函数确保不会在用户每次按键时都检查禁止词汇。那将是大量的检查!相反,我们会等到用户停止输入后再执行操作。

接下来是一个 containsForbiddenWords 函数。顾名思义,该函数在传递给它的文本中包含任何禁用词时返回 true。我们将两个值都转为小写,以确保比较不区分大小写。

updateUI 函数确定聊天框中是否存在任何禁用词。如果存在,它会禁用发送按钮并向聊天框的父 div 添加一个 CSS 类(forbidden-div)。

脚本最后注册了两个事件监听器:

  1. 第一个触发在 keyup 事件上。它检查修改的元素是否是我们的目标(聊天窗口),然后调用 updateUI 函数。
  2. 第二个事件监听器监听我们的目标上的 keydown 事件。具体来说,它在文本区域中有一个禁用词时,会阻止浏览器的默认操作(在这种情况下为表单提交)。

这有效地阻止了包含禁用词的消息被发送。

值得注意的是,我们使用了事件委托,因为 ChatGPT 界面是一个单页面应用(SPA)。在 SPA 中,用户界面的部分会根据用户交互动态替换,这可能会意外地解除绑定到这些元素的任何事件监听器。

步骤4:添加样式

虽然我们扩展的核心功能是防止特定的提交行为,但让用户能立即识别出为什么他们的操作被阻止也非常重要。让我们添加一些样式,以提供视觉提示并增强用户体验。

下面是我们要使用的样式规则。请将其添加到 styles.css 文件中:

.forbidden-div {
  border: 2px solid red !important;
  background-color: #ffe6e6 !important;
}

这样,每当检测到禁用词时,输入区域会立即显示出醒目的红色边框和微妙的红色背景。这立即引起了注意,并表明出现了问题。通过在父级 div 上切换一个类,我们可以轻松地打开或关闭这一功能。

值得注意的是 !important 标志。当你处理不属于你的网页时——比如在这种情况下与 ChatGPT——现有的样式可能非常具体。为确保我们的样式具有优先级并被正确应用,!important 标志会覆盖由于现有样式特异性而可能产生的任何潜在冲突。

步骤5:测试扩展

最后一步:填充我们的扩展应该监控的禁用词列表。我们可以在 forbiddenWords.js 中添加这些词:

const forbiddenWords = [
  "my-company.com",
  "SitePoint",
  "Jim",
];

现在我们的自定义 Google Chrome 扩展已经全部设置好了,是时候测试其功能,确保一切都按预期运行了。

  1. 打开 Chrome 浏览器,然后在地址栏中导航到 chrome://extensions/
  2. 在页面右上角打开“开发者模式”开关。
  3. 点击现在可见的“加载未打包的扩展”按钮。
  4. 导航到并选择您的扩展目录(在我们的例子中是 chatgpt-molly-guard),然后点击“选择”。我们的扩展现在应该出现在已安装扩展的列表中。

image.png

现在,为了测试功能,请导航到 ChatGPT,刷新页面,然后尝试输入您的限制词,看看扩展是否按预期行为。

如果一切都按计划进行,您应该会看到如下图所示的情况。

image.png

如果您对扩展代码进行了任何更改——例如更新单词列表——请确保点击扩展页面上扩展卡片右下角的环形箭头。这将重新加载扩展。然后,需要重新加载扩展正在针对的页面。

image.png

进一步拓展

我们当前的基础 Chrome 扩展已经满足了其目的,但总有改进的空间。如果您渴望进一步完善扩展并扩展其功能,以下有一些建议。

单词列表编辑的用户界面

目前,我们的扩展依赖于预定义的受限单词列表。实现一个用户友好的界面将允许用户动态地添加、删除或修改单词。这可以通过一个弹出 UI(浏览器操作)来完成,该 UI 在点击扩展图标时打开,用户可以在其中管理他们的列表。您还需要将单词持久化到存储中。

处理鼠标粘贴事件

虽然我们的扩展检测到按键操作,但用户可以通过使用鼠标的右键菜单粘贴敏感信息来绕过这一点。为了堵住这个漏洞,我们可以添加一个用于粘贴事件的事件监听器(或者两者都监听输入事件)。这将确保无论信息是键入还是粘贴的,过滤器都能保持强健。

情境性覆盖

阻止某些词可能有点过于笼统。例如,我可能想阻止提到“Jim”(我的名字),但没有问题提到“Jim Carey”。为解决这个问题,考虑引入一个功能,该功能将在下一个提交事件发生之前禁用 molly-guard。

总结

如我们所见,构建自己的 Google Chrome 扩展并不是不可逾越的挑战。我们从一个明确的目标开始:为 ChatGPT 创建一个保护层,确保敏感信息保密。在本教程中,我们看到了如何通过少量的文件和一些代码来实现一个功能强大且有用的浏览器扩展。

交流

首发于公众号 大迁世界,欢迎关注。📝 每周一篇实用的前端文章 🛠️ 分享值得关注的开发工具 ❓ 有疑问?我来回答

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。


王大冶
68.1k 声望105k 粉丝