首发于 ColorGamer

一起来做浏览器扩展-只打开一个标签页

注:因为firefox, edge都兼容了chrome的扩展,所以,chrome的很多接口都可以直接在它俩的扩展中使用。本文就以chrome api为例

只开一个窗口,在一些应用上是比较常见的。比如扩展在使用同一个本地数据源,如果可以打开多个窗口,可能造成数据混乱的问题。

在扩展里处理这个问题非常容易,毕竟浏览器提供了一些方法。

应用举例

  • 当点击浏览器右上角的扩展图标时,打开一个新窗口运行扩展内容。
  • 当再次点击这个图标时,只是切回已经打开的窗口,而不会打开新窗口

监听图标点击

使用浏览器提供的方法,在background js中监听:

chrome.browserAction.onClicked.addListener(function (tab) {
	// 当点击扩展图标时,执行...
});

打开新页面

要开页面,需要用到tabs.create方法

chrome.browserAction.onClicked.addListener(function (tab) {
	chrome.tabs.create({
		url: chrome.extension.getURL("index.html")
	}, function(tab) {})
});

chrome.tabs.create 有两个参数

  • 第一个是参数,其中url是要打开的页面地址。在扩展里,使用 chrome.extension.getURL() ,就可以得到文件在扩展里的路径
  • 第二个参数,是一个回调函数,参数是打开的tab信息
关于更多参数,可以参考官方文档: developer.chrome.com/do

检查是否已打已经打开窗口

以上两点为打开页面的两个基础方法,要做到只开一个窗口,我们还需要做一些工作,比如记下已经打开的窗口id。

要记录这个id,首先我们要知道,一个扩展的background js,是单例的,不管你的扩展在多少的页面上运行,background只有一个。所有的页面和background通信,其实都是在和同一个对象通信,而且它一直在内存里。因此,我们在background里申明的变量,它会一直存在着,直到扩展被重置,删除或是浏览器关闭。

那么,我们在background里申明一个变量来保存打开窗口的信息就可以满足需求。

let openerTabId = 0;
chrome.browserAction.onClicked.addListener(function (tab) {
	chrome.tabs.create({
		url: chrome.extension.getURL("index.html")
	}, function(tab) {
		openerTabId = tab.id;
});

下面讲讲检查流程:

  1. 点击扩展图标打开新窗口时判断是否有记录的tabid,如果没有创建新的页面。如果有,进入第2步。
  2. 通过 chrome.tabs.get() 函数获取记录tabid对应的tab信息,如果未找到,创建新的页面。如果有,进入第3步。
  3. 更新对应tab的窗口和tab,将它们置为焦点状态。窗口即window,因为浏览器是可以打开多窗口的。比如,扩展打开在1号窗口里,你在2号窗口里点击图标想打开扩展,这样浏览器会转到1号窗口并打开对应的tab页。
let openerTabId = 0;
chrome.browserAction.onClicked.addListener(function (tab) {
	if (openerTabId > 0) {
		chrome.tabs.get(openerTabId, function(t) {
			if (t) {
				chrome.windows.update(t.windowId, {focused: true}); // 更新窗口
				chrome.tabs.update(openerTabId, {active: true});  // 更新tab
			} else {
				chrome.tabs.create({
					url: chrome.extension.getURL("index.html")
				}, function(tab) {
					openerTabId = tab.id;
	} else {
		chrome.tabs.create({