管理标签页

构建您的第一个标签页管理器。

概览

本教程将构建一个标签页管理器,用于整理 Chrome 扩展程序和 Chrome 应用商店文档标签页。

标签页管理器扩展程序弹出式窗口
标签页管理器扩展程序

在本指南中,我们将介绍如何执行以下操作:

  • 使用 Action API 创建扩展程序弹出式窗口。
  • 使用 Tabs API 查询特定标签页。
  • 通过缩小主机权限来保护用户隐私。
  • 更改标签页的焦点。
  • 将标签页移至同一窗口并将其分组。
  • 使用 TabGroups API 重命名标签页分组。

前期准备

本指南假定您具备基本的 Web 开发经验。我们建议您查看 Hello World,了解扩展程序开发工作流程。

构建扩展程序

首先,创建一个名为 tabs-manager 的新目录来存放扩展程序的文件。如果您愿意,可以前往 GitHub 下载完整的源代码。

第 1 步:添加扩展程序数据和图标

创建一个名为 manifest.json 的文件,并添加以下代码:

{
  "manifest_version": 3,
  "name": "Tab Manager for Chrome Dev Docs",
  "version": "1.0",
  "icons": {
    "16": "images/icon-16.png",
    "32": "images/icon-32.png",
    "48": "images/icon-48.png",
    "128": "images/icon-128.png"
  }
}

如需详细了解这些清单键,请参阅“阅读时间”教程,其中详细介绍了扩展程序的元数据图标

创建一个 images 文件夹,然后将下载的图标下载到该文件夹中。

第 2 步:创建并设置弹出式窗口的样式

Action API 用于控制扩展程序操作(工具栏图标)。当用户点击扩展程序操作时,它会运行一些代码或打开一个弹出式窗口,如本例所示。首先,在 manifest.json 中声明弹出式窗口:

{
  "action": {
    "default_popup": "popup.html"
  }
}

弹出式窗口与网页类似,但有一个例外情况:它无法运行内嵌 JavaScript。创建一个 popup.html 文件,并添加以下代码。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="./popup.css" />
  </head>
  <body>
    <template id="li_template">
      <li>
        <a>
          <h3 class="title">Tab Title</h3>
          <p class="pathname">Tab Pathname</p>
        </a>
      </li>
    </template>

    <h1>Google Dev Docs</h1>
    <button>Group Tabs</button>
    <ul></ul>

    <script src="./popup.js" type="module"></script>
  </body>
</html>

接下来,您将为弹出式窗口设置样式。创建一个 popup.css 文件,并添加以下代码。

body {
  width: 20rem;
}

ul {
  list-style-type: none;
  padding-inline-start: 0;
  margin: 1rem 0;
}

li {
  padding: 0.25rem;
}
li:nth-child(odd) {
  background: #80808030;
}
li:nth-child(even) {
  background: #ffffff;
}

h3,
p {
  margin: 0;
}

第 3 步:管理标签页

借助 Tabs API,扩展程序可以在浏览器中创建、查询、修改和重新排列标签页。

请求权限

无需请求任何权限,即可使用 Tabs API 中的许多方法。不过,我们需要访问标签页的 titleURL;这些敏感属性需要权限。我们可以请求 "tabs" 权限,但这会授予对所有标签页的敏感属性的访问权限。由于我们只管理特定网站的标签页,因此我们将请求有限的托管方权限。

通过限制主机权限,我们可以向特定网站授予提升后的权限,从而保护用户隐私。这将授予对 titleURL 属性以及其他功能的访问权限。将突出显示的代码添加到 manifest.json 文件中:

{
  "host_permissions": [
    "https://developer.chrome.com/*"
  ]
}

💡? 标签页权限和主机权限之间的主要区别是什么?

"tabs" 权限和主机权限都有缺点。

"tabs" 权限可让扩展程序读取所有标签页中的敏感数据。随着时间的推移,这些信息可能会被用于收集用户的浏览记录。因此,如果您请求此权限,Chrome 会在安装时显示以下警告消息:

标签页权限警告对话框

借助主机权限,扩展程序可以读取和查询匹配标签页的敏感属性,还可以在这些标签页中注入脚本。用户在安装时会看到以下警告消息:

主机权限警告对话框

这些警告可能会让用户感到担忧。为了提供更好的新手入门体验,我们建议您实现可选权限

查询标签页

您可以使用 tabs.query() 方法从特定网址检索标签页。创建一个 popup.js 文件,并添加以下代码:

const tabs = await chrome.tabs.query({
  url: [
    "https://developer.chrome.com/docs/webstore/*",
    "https://developer.chrome.com/docs/extensions/*",
  ]
});

💡? 我可以在弹出式窗口中直接使用 Chrome API 吗?

弹出式窗口和其他扩展程序页面可以调用任何 Chrome API,因为它们是从 Chrome 架构中提供的。例如 chrome-extension://EXTENSION_ID/popup.html

将焦点置于标签页

首先,该扩展程序会按字母顺序对标签页名称(包含的 HTML 网页的标题)进行排序。然后,当点击某个列表项时,它会使用 tabs.update() 将焦点移至该标签页,并使用 windows.update() 将该窗口置于前台。将以下代码添加到 popup.js 文件中:

...
const collator = new Intl.Collator();
tabs.sort((a, b) => collator.compare(a.title, b.title));

const template = document.getElementById("li_template");
const elements = new Set();
for (const tab of tabs) {
  const element = template.content.firstElementChild.cloneNode(true);

  const title = tab.title.split("-")[0].trim();
  const pathname = new URL(tab.url).pathname.slice("/docs".length);

  element.querySelector(".title").textContent = title;
  element.querySelector(".pathname").textContent = pathname;
  element.querySelector("a").addEventListener("click", async () => {
    // need to focus window as well as the active tab
    await chrome.tabs.update(tab.id, { active: true });
    await chrome.windows.update(tab.windowId, { focused: true });
  });

  elements.add(element);
}
document.querySelector("ul").append(...elements);
...

💡? 此代码中使用的有趣 JavaScript

  • 用于按用户的首选语言对标签页数组进行排序的排序器
  • 模板标记用于定义可克隆的 HTML 元素,而不是使用 document.createElement() 创建每个项。
  • 用于创建和解析网址的网址构造函数
  • 用于在 append() 调用中将一组元素转换为参数的展开语法

为标签页分组

借助 TabGroups API,扩展程序可以为组命名并选择背景颜色。添加突出显示的代码,将 "tabGroups" 权限添加到清单中:

{
  "permissions": [
    "tabGroups"
  ]
}

popup.js 中,添加以下代码以创建一个按钮,该按钮将使用 tabs.group() 对所有标签页进行分组,并将其移至当前窗口。

const button = document.querySelector("button");
button.addEventListener("click", async () => {
  const tabIds = tabs.map(({ id }) => id);
  if (tabIds.length) {
    const group = await chrome.tabs.group({ tabIds });
    await chrome.tabGroups.update(group, { title: "DOCS" });
  }
});

测试是否生效

验证项目的文件结构是否与以下目录树一致:

标签页管理器文件夹的内容:manifest.json、popup.js、popup.css、popup.html 和 images 文件夹。

在本地加载扩展程序

如需在开发者模式下加载未封装的扩展程序,请按照 Hello World 中的步骤操作。

打开几个文档页面

在不同的窗口中打开以下文档:

点击弹出式窗口。它应如下所示:

标签页管理器扩展程序弹出式窗口
标签页管理器扩展程序弹出式窗口

点击“分组标签页”按钮。它应如下所示:

标签页管理器 - 分组标签页
使用“标签页管理器”扩展程序对标签页进行分组

🎯? 可能的改进

根据您今天学到的内容,尝试实现以下任一操作:

  • 自定义弹出式窗口样式表。
  • 更改标签页分组的颜色和标题。
  • 管理其他文档网站的标签页。
  • 添加了对取消分组标签页的支持。

继续构建!

恭喜您完成本教程 🎉?。请完成本系列的其他教程,不断提升您的技能:

扩展程序 学习内容
阅读时间 自动在每个网页上插入元素。
对焦模式 在点击扩展程序操作后,在当前网页上运行代码。

继续探索

希望您喜欢构建此 Chrome 扩展程序,并期待您继续学习 Chrome 开发。我们建议您采用以下学习路径:

  • 开发者指南中包含数十个指向与高级扩展程序创建相关的文档的链接。
  • 除了开放网络上提供的强大 API 之外,扩展程序还可以访问其他 API。 Chrome API 文档详细介绍了每个 API。