使用 chrome.tabs 构建您的第一个 Chrome 扩展程序
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
浏览器扩展程序是一种很棒的方式,它能让你基于前端 Web 开发的基础组件(HTML、CSS 和 JavaScript)进行扩展。事实上,它们正是我进入前端 Web 开发的入门途径。我真正喜欢它们的一点是,你只需要掌握创建网页所需的那些技术,然后通过集成浏览器 API,你就能开发出非常实用的应用程序!
在本教程中,我们将制作一个 Chrome 扩展程序,它可以重新排列浏览器中的标签页,使其按 URL 排序。这样,如果您打开了许多来自不同网站的标签页,就可以使用此扩展程序将来自同一网站的所有标签页集中显示在 Chrome 的顶部栏中,方便您轻松浏览。
本教程假定读者已掌握 JavaScript 基础知识,建议了解回调函数和方法Array.prototype.sort。本教程面向浏览器扩展程序编写新手。
添加扩展清单
每个浏览器扩展程序首先都需要一个清单文件。清单文件是一个 JSON 文件,它就像是“应用程序的蓝图”,它会告诉你一些信息,例如使用哪张图片作为扩展程序的图标、扩展程序运行哪些代码,以及应用程序需要访问 Chrome 的哪些部分,例如网页历史记录或书签。
如果您正在按照本教程操作,请创建一个名为 `<folder_name>` 的文件夹tab-sorter,并在该文件夹下创建一个名为 `<folder_name>` 的文件夹app,然后在`<folder_name>` 文件夹中添加包含以下代码的app文件 :manifest.json
{
"manifest_version": 2,
"name": "Tab Sorter",
"version": "1.0.0",
"description": "Rearrange your tabs by URL"
}
现在我们有了一个清单文件,其中包含了扩展程序的名称、版本和简短描述。实际上,有了它,我们实际上已经拥有了一个可以加载到 Chrome 中的扩展程序,让我们来试试吧!首先,访问 URL ,这是您可以在 Chrome 中管理扩展程序的地方。然后,打开“开发者模式”chrome://extensions开关:
然后,您会在左上角看到一个“加载已解压文件”的按钮,点击它可以从您的某个文件夹加载扩展程序。点击该按钮并选择文件夹tab-sorter/app,现在您应该可以在顶部栏的地址栏右侧看到一个带有“T”的图标。这就是您正在创建的扩展程序。
该扩展程序目前除了显示一个下拉选项列表外,没有任何其他功能,所以我们来改变一下,给它添加一个弹出窗口,也就是点击扩展程序图标时会弹出的 HTML 页面。在app文件夹中,将以下 HTML 代码添加到名为 `<filename>` 的文件中popup.html:
<html>
<head></head>
<body>
<h1>We're running a Chrome extension!</h1>
</body>
</html>
我们有一个可以弹出显示的页面!但如果我们现在直接重新加载扩展程序,它实际上并不会执行任何操作popup.html。为了使用该 HTML 文件作为弹出窗口,我们需要将 popup.html 添加到浏览器操作的清单文件中,这是指定扩展程序将使用的代码的一种方法。
在文件中manifest.json,添加以下browser_action内容,现在它应该看起来像这样:
{
"manifest_version": 2,
"name": "Tab Sorter",
"version": "1.0.0",
"description": "Rearrange your tabs by domain name",
+ "browser_action": {
+ "default_popup": "popup.html"
+ }
}
该browser_action.default_popup字段告诉我们,点击应用图标后,popup.html 的内容会显示在浏览器顶部栏下方的一个小窗口中。现在chrome://extensions,再次点击“加载已解压的文件”流程,或者直接点击页面上扩展程序面板中的旋转箭头图标来重新加载扩展程序。然后,我们应该就能看到弹出窗口了!
现在我们有了一个弹出窗口,就像在普通的 HTML 网页中一样,我们可以在弹出窗口中运行 JavaScript,使应用程序执行我们在普通的 HTML/CSS/JS Web 应用程序中可以执行的所有相同操作。
但与普通网页不同,在扩展程序中,我们可以使用浏览器 API来操作浏览器的不同部分,例如用户的标签页。我们将在下一节开始讲解!
不过在此之前,我们的应用必须要有图标!图标可以是任何高度和宽度相同的图片,幸运的是,谷歌在这个页面上提供了一套免费的图标,而且采用的是宽松的 MIT 许可证!下载那个看起来像左右箭头的 128x128 像素大小的图标,并将其保存到指定位置tab-sorter/app/128.png。然后,将清单文件中的相应部分修改browser_action为:
"browser_action": {
- "default_popup": "popup.html"
+ "default_popup": "popup.html",
+ "default_icon": {
+ "128": "128.png"
+ }
}
现在,如果您再次重新加载扩展程序,应该会看到以下内容:
我们目前的进展体现在提交 1中。
现在让我们让扩展程序与浏览器标签页协同工作!
探索 chrome.tabs API
为了对标签页进行排序,我们需要一个能够与 Google Chrome 标签页“交互”的 API。我们希望能够执行的操作包括:
- 列出当前浏览器窗口中的所有标签页
- 查看每个标签页所在的网站,以便我们按网址对标签页进行排序。
- 调整浏览器顶部栏标签页的顺序,使它们按 URL 字母顺序排列。
Google Chrome 提供了大量的 API,让你能够使用不同的浏览器功能,你可以在这里查看完整列表!我们需要的是 `<API>` chrome.tabs,你可以在这里找到它的文档!
如果您查看 Chrome API 的目录,例如tabs,您可以看到该 API 使用的不同类型的 JavaScript 对象、您可以使用的 API 方法以及您可以让 Chrome 扩展程序监听和响应的事件。
我们来看一下类型Tab,也就是我们将要使用的数据类型。Tab对象告诉我们浏览器中单个标签页的信息。这些信息包括:
id一个唯一标识标签的数字windowId这会告诉我们标签页位于哪个窗口中。highlighted一个布尔值,用于告诉我们给定的标签页是否是我们正在查看的标签页。- 以及我们最需要的主要字段
url,它告诉我们标签页所在的 URL。
既然我们已经找到了浏览器标签页对象,并且知道它有一个url字段,那么我们扩展程序的伪代码将如下所示:
let tabs = getTheTabs();
sortTheTabs(by Tab.url);
for (let i = 0; i < tabs.length; i++) {
moveTabTo(that tabs index inside the sorted array);
}
所以,我们需要将伪代码转换成实际代码的部分是getTheTabs:,,moveTabTo以及一个by Tab.url按 URL 对标签页进行排序的函数。首先,我们来寻找一个获取当前浏览器窗口中所有标签页的函数。
列出标签页
在API 目录的“方法”部分,有很多方法,例如通过 ID 号获取单个选项卡、打开和关闭选项卡、导航到不同的 URL,甚至可以使用 更改选项卡的 CSS insertCSS。
我们需要的获取当前窗口中所有标签页列表的方法是chrome.tabs.query,其函数签名如下:
function query(queryInfo, callback)
该queryInfo参数是一个 JavaScript 对象,它提供了用于缩小我们想要获取的标签页范围的选项。因此,要仅获取用户当前浏览器窗口中的标签页(例如,如果用户打开了多个 Chrome 窗口),我们的queryInfo对象将如下所示:
{windowId: chrome.windows.WINDOW_ID_CURRENT}
然后我们来看参数callback。tabs.query以及许多其他 Google Chrome API 方法都是异步的。为了确保在从浏览器获取数据时不会阻塞 JavaScript 运行时,当我们运行 `getTabList()`chrome.tabs.query或类似方法时,我们会让 Chrome 开始使用 `getTabList()` 获取我们请求的标签页queryInfo,然后让 JavaScript 继续执行其他代码。之后,当 Chrome 返回标签页列表时,回调函数就会运行,让我们能够操作这些标签页。
所以,我们的代码不再是这样的:
let tabs = chrome.tabs.query({windowId: chrome.windows.WINDOW_ID_CURRENT});
// sort the tabs
// rearrange the tabs
它看起来会更像:
chrome.tabs.query({windowId: chrome.windows.WINDOW_ID_CURRENT}, (tabs) => {
// sort the tabs
// rearrange the tabs
});
我们来chrome.tabs.query尝试一下,让弹出窗口以列表形式显示我们当前正在使用的所有标签页!在 `<body>` 标签内popup.html,添加以下脚本标签:
<script type="text/javascript" src="popup.js"></script>
然后创建一个新文件,popup.js并添加以下代码:
chrome.tabs.query({windowId: chrome.windows.WINDOW_ID_CURRENT}, (tabs) => {
document.write(`<h3>The tabs you're on are:</h3>`);
document.write('<ul>');
for (let i = 0; i < tabs.length; i++) {
document.write(`<li>${tabs[i].url}</li>`);
}
document.write('</ul>');
});
请前往[此处chrome://extensions插入链接],再次重新加载扩展程序,点击弹出窗口,您将看到:
为什么我们所有的列表项都显示“无”?这是因为我们的应用没有请求使用标签页数据的权限undefined,所以我们无法看到标签页上的 URL 。我们需要在扩展程序的清单文件中设置该权限。
转到你的manifest.json,并添加该行permissions: ["tabs"]
{
"manifest_version": 2,
"name": "Tab Sorter",
"version": "1.0.0",
"description": "Rearrange your tabs by domain name",
+ "permissions": ["tabs"],
"browser_action": {
"default_popup": "popup.html"
}
}
在浏览器扩展程序商店中,用户可以看到扩展程序需要哪些权限。因此,在 Chrome 允许扩展程序访问每个标签页中的 URL 之前,tabs必须先在清单文件中列出相应的权限。现在,权限已添加到清单文件中,请再次重新加载 Chrome 扩展程序,您应该会看到:
好了!我们现在可以获取所有标签页了!现在,我们应用程序的整体伪代码只剩下两个空白需要填写:标签页排序和标签页移动。所以现在我们的伪代码如下所示:
chrome.tabs.query({windowId: chrome.windows.WINDOW_ID_CURRENT}, (tabs) => {
sortTheTabs(by Tab.url);
for (let i = 0; i < tabs.length; i++) {
moveTabTo(tabs[i], i);
}
});
我们目前的进展在Commit 2中。
对标签页进行排序
现在我们有了这些Tab,接下来要弄清楚的是如何对它们进行排序,使它们按 URL 的顺序排列。
正如我们在上一节中看到的,我们有一个Tab.url字段可以用来查看每个标签页的 URL。因此,要按 URL 字母顺序对我们的标签页数组进行排序,我们可以使用 JavaScript 的核心Array.prototype.sort方法。
如果你之前没用过Array.prototype.sort,它允许你按照你想要的顺序重新排列数组中的元素。例如,如果你运行:
let a = ['JavaScript', 'C++', 'Go'];
a.sort();
console.log(a);
那么数组中的字符串现在将按['C++', 'Go', 'JavaScript']字母顺序排序。
由于我们要对对象而不是字符串或数字进行排序,因此还需要传入一个比较函数,该函数接收两个制表符并告诉我们哪个制表符应该放在数组的前面。运行结果如下所示:
tabs.sort(byAlphabeticalURLOrder);
根据语法规则Array.prototype.sort,当使用比较函数比较数组中的两个元素时:
- 如果函数返回的数字小于 0,则将数组中的元素移动到第二个元素之前。
- 如果函数返回的数字大于 0,则数组中的元素将被移动,使得第一个元素位于第二个元素之后。
- 如果比较函数返回0,则认为这两个元素的值相等,并保持在数组中原来的位置。
所以,当两个标签页被传递给我们的比较函数时:
- 如果第一个标签页的 URL 在字母顺序上排在第二个标签页的 URL 之前,则返回 -1,这样第一个标签页在数组中就排在前面。
- 如果第二个标签页的 URL 在字母顺序上排在第一个标签页的 URL 之前,则返回 1,表示第二个标签页在数组中排在前面。
- 如果两个标签页的 URL 完全相同,则返回 0,并且它们的顺序保持不变。
所以让我们把它转换成代码。将此函数添加到代码顶部。popup.js
function byAlphabeticalURLOrder(tab1, tab2) {
if (tab1.url < tab2.url) {
return -1;
} else if (tab1.url > tab2.url) {
return 1;
}
return 0;
}
我们已经有了比较函数!现在让我们尝试在上一节中创建的列表函数中使用它:
chrome.tabs.query({windowId: chrome.windows.WINDOW_ID_CURRENT}, (tabs) => {
+ tabs.sort(byAlphabeticalURLOrder);
+
document.write(`<h3>The tabs you're on are:</h3>`);
document.write('<ul>');
for (let i = 0; i < tabs.length; i++) {
document.write(`<li>${tabs[i].url}</li>`);
}
document.write('</ul>');
});
重新加载扩展程序chrome://extensions,再次打开扩展程序的弹出窗口,现在它应该看起来像这样!
太好了,我们已经整理好了标签页列表!现在,为了让标签页在浏览器顶部栏中重新排列,我们只需要再添加一个 Chrome 函数!
我们目前的进展体现在提交 3中。
移动标签页
回顾 Chrome 标签页 API 的文档,我们可以发现该 API 提供了我们想要的用于在顶部栏移动标签页的函数chrome.tabs.move!该函数的签名如下:
function move(tabIds, moveProperties, callback);
- 对于该
tabIds参数,每个选项卡都有一个唯一的 ID 号Tab.id。因此,如果我们要移动 ID 号为 250 的选项卡,我们会这样做:move(250, moveProperties, callback); moveProperties是一个描述标签页移动到哪里的对象。因此,我们可以通过调用 `moving_left_tab` 函数,将 ID 为 250 的标签页移动到浏览器窗口的最左侧move(250, {index: 0}, callback);。请注意,标签页的索引从 0 开始,因此窗口中最左侧的标签页的索引为 0。- 最后,我们来看可选的回调函数
callback。与之前的函数一样query,该move函数是异步的,因此如果我们希望在标签页移动后立即执行某些操作,则需要在回调函数中运行该操作。
我们来尝试一下移动标签页,只需将按 URL 字母顺序排列的第一个标签页移动到窗口的最左侧即可。编辑方法popup.js如下:
chrome.tabs.query({windowId: chrome.windows.WINDOW_ID_CURRENT}, (tabs) => {
tabs.sort(byAlphabeticalURLOrder);
+ chrome.tabs.move(tabs[0].id, {index: 0});
-
- document.write(`<h3>The tabs you're on are:</h3>`);
- document.write('<ul>');
- for (let i = 0; i < tabs.length; i++) {
- document.write(`<li>${tabs[i].url}</li>`);
- }
- document.write('</ul>');
});
要尝试此功能,请重新加载您的扩展程序chrome://extensions,并将该标签页移动到浏览器的最右侧。然后,单击浏览器扩展程序的图标,该标签页应该会移动到从左侧数第一个标签页。
因为我们已经运行了tabs.sort,数组中的所有标签tabs现在都按照我们希望它们在浏览器顶部栏中的顺序排列;数组中的第一个标签应该是顶部栏中最左边的标签,数组中的第二个标签应该是顶部栏中的第二个标签,依此类推!
因此,如果数组中所有标签页都按我们想要的顺序排列,我们可以使用以下循环将它们全部按 URL 字母顺序排列:
chrome.tabs.query({windowId: chrome.windows.WINDOW_ID_CURRENT}, (tabs) => {
tabs.sort(byAlphabeticalURLOrder);
- chrome.tabs.move(tabs[0].id, {index: 0});
+ for (let i = 0; i < tabs.length; i++) {
+ chrome.tabs.move(tabs[i].id, {index: i});
+ }
});
只需在浏览器中重新加载一次扩展程序chrome://extensions,点击其图标,您的所有标签页现在应该都会按 URL 字母顺序重新排列!
不过您可能会注意到一个有点不寻常的地方:例如,如果您的顶部栏同时显示 twitter.com 和www.google.com,即使 Google 在字母顺序上排在 Twitter 前面,重新排列的标签页中 Twitter 也会排在前面。这是因为 URL 中“www”位于“Twitter”之后。因此,如果我们在一家真正的公司开发这项功能,下一步的用户体验改进措施可能是调整我们的比较函数,使其忽略“https://和” www.。
我会把这个问题,以及其他改善用户体验的想法,留给大家去思考和解决;我鼓励大家继续尝试这个应用程序和chrome.tabsAPI,但就目前而言,我们已经有了一个很棒的 MVP(最小可行产品)!
如果你是第一次编写浏览器扩展程序,恭喜你!希望你以后能继续开发更多!我强烈建议你查看一下Google Chrome 的API 索引,了解你的浏览器扩展程序可以使用的其他各种 API!🎊
本教程的最终版本在提交 4中。
文章来源:https://dev.to/andyhaskell/build-your-first-chrome-extension-with-chrome-tabs-3625





