Saber 酱的抱枕

Fly me to the moon

04/14
2017
学习

制作chrome扩展的一些经验

Chrome-Extensions chrome扩展

本文略微记录一下开发chrome扩展的经验,免得以后用到了还要再去查一遍文档。注意这不是教程,只是一点人生的经验……教程可以参考这里

1.文件结构:

在扩展的根目录必须有个manifest.json文件,这个文件很重要,参数可以去文档里看。

其他的所有文件可以放在根目录,也可以建立文件夹存放。
扩展的图标可以用jpg或者png格式;官方建议是不要把图标占满画布,而是在四周留下一点空白。
一般我们需要一个在后台默默运行的js,通常叫做background.js,它能使用所有chrome扩展的API。
通常我们也需要有一个在前台运行的js,可以叫做content.js。这个js会被加载进前台页面执行,它只能使用很少的chrome扩展的API。而且它通常只能访问dom结构,不能直接使用页面上定义的函数。
如果需要也可以建立一个活动页面,一般叫做popup.html。
如果需要也可以建立一个选项页面,一般叫做options.html。
以上这些都需要在manifest.json里定义。
其他的文件可以自行发挥,比如html文件、css文件、图片等,有需要就可以建立,然后自行调用即可。

在background的参数里设置"persistent": false可将扩展作为event page,可以减少一些内存占用。

我使用过的一个文件示例:

{
	"name": "扩展名称",
	"version": "0.1.0",
	"manifest_version": 2,
	"description": "扩展名称,扩展简介",
	"icons": {
		"16": "icon/icon_16.png",
		"19": "icon/icon_19.png",
		"32": "icon/icon_32.png",
		"38": "icon/icon_38.png",
		"48": "icon/icon_48.png",
		"128": "icon/icon_128.png"
	},
	"browser_action": {
		"default_icon": {
			"16": "icon/icon_16.png",
			"19": "icon/icon_19.png",
			"32": "icon/icon_32.png",
			"38": "icon/icon_38.png",
			"48": "icon/icon_48.png",
			"128": "icon/icon_128.png"
		},
		"default_title": "在浏览器工具栏上的标题"
	},
	"content_scripts": [{
		"matches": ["*://*.baidu.com/*"],
		"js": ["content.js"],
		"run_at": "document_end"
	}],
	"background": {
		"scripts": ["background.js"],
		"persistent": false
	},
	"permissions": [
		"contextMenus", "tabs", "*://*.baidu.com/*"
	]
}

2.前台与后台通信问题(消息传递)

2.1【前台主动向后台发送消息】

因为前台脚本只能使用很少的chrome扩展的API,所以有时候我们用前台脚本获取信息,然后传递给后台。这时要使用chrome.runtime.sendMessage这个API。(后台脚本是在浏览器运行环境里的)

chrome.runtime.sendMessage("loaded", function(response) {});

第一个参数是要发送的消息,可以是任何数据类型。我们最常用的可能是对象、数组、字符串、数字类型等。
第二个参数是回调函数,其参数response是回调函数接收到的返回值。

2.2【后台主动向前台发送消息】

这时候和上面有区别,因为前台脚本不是在浏览器的runtime里面的,所以向前台发送消息要使用tabs的API,也就是chrome.tabs.sendMessage。

chrome.tabs.sendMessage(tab.id, "getInfo", function(response) {});

这个API多了个参数,也就是参数1。我们要向某个tab发送消息,需要这个tab的id。

如果我们不知道tab的id怎么办?可以先用chrome.tabs.query获取【当前激活的标签页】的tab对象,然后取得tab的id属性。如下:

chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
    chrome.tabs.sendMessage(tab.id, "getInfo", function(response) {});
});

不过有些情况下可能不需要特地去获取tab的id。

2.3【前后台接收消息】

这个前后台是一致的,都是监听chrome.runtime.onMessage事件:

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
	sendResponse("xxx");;
});

接收到消息后,我们可以直接用sendResponse方法向发送者返回消息。
发送者通过sendMessage API的回调函数里的response来接收返回的消息。

3.创建右键菜单

为了方便用户,我们可能需要在右键菜单里添加自己的菜单。使用chrome.contextMenus API(这个API只有后台脚本能使用):

chrome.contextMenus.create({
	'id': 'getImages',
	'type': 'normal',
	'title': '下载页面中所有图片',
	'contexts': ['all'],
	'documentUrlPatterns': ['*://*.xx.com/*']
});
// contexts参数为all,即在页面的所有元素上右键都会显示该菜单
// documentUrlPatterns为匹配url,在符合的页面上才创建这个右键菜单

那我们如何知道用户点击了这个菜单呢?点击任意右键菜单都会触发onClicked事件,我们可以通过判断被点击的菜单的id来知道点击的是不是我们的菜单。

chrome.contextMenus.onClicked.addListener(function(info, tab) {	//第二个参数是tab对象
	if (info.menuItemId == 'getImages') {		//info.menuItemId里面就是被点击的菜单项的id
		chrome.tabs.sendMessage(tab.id, "xxx", function(response) {});
	}
});

上面的例子中我发送了一条消息,提醒大家注意chrome.contextMenus.onClicked的第二个参数是tab对象,我们可以直接取得tab.id。这样,后台就能知道点击了菜单的是哪个页面。

4.打开扩展里的html页面

平时我们打开新页面,会使用window.open(),但如果chrome扩展想要打开自己文件夹里的某个html文件,就不适合用window.open了。

首先,前台页面不能用window.open()来打开chrome扩展里的页面,尝试打开的话是空标签页(about:blank)。后台页面倒是可以用window.open()来打开chrome扩展里的页面,但要获取url也很难。注意如下的url:

这时候需要使用chrome.tabs.create()方法。

// 打开扩展文件夹里的lookme.html
chrome.tabs.create({
	url: "lookme.html"
});

在后台脚本里使用chrome.tabs.create()打开一个相对路径的话,就是相对于调用这个API的后台脚本(或后台页面)的路径。

注意,如果打开的页面是扩展自带的页面的话,那么这个页面就可以使用浏览器的全部 API。

当然chrome.tabs.create()也可以用于打开任意的外部页面。

5.下载API

chrome.downloads.download({
	url: url,
	filename: fileName,
	conflictAction: 'uniquify',
	saveAs: false
});

上面的常用参数我解释一下:
url就是要下载的文件的url,该参数是必须的。
filename参数是保存时使用的文件名。该参数是可选的,注意“filename”是小写的。
conflictAction表示文件重复的话怎么处理(有同名文件),该参数是可选的。uniquify就是不覆盖,而是在文件名后加上序号再保存。

下载的文件会保存在chrome设置的下载文件夹里。如果我们需要创建文件夹,那么可以在文件名里包含斜杠“/”,如“saber/1.jpg”,这样chrome会自动在下载文件夹里创建一个saber文件夹。但注意不能在路径的第一个字符使用“/”,因为这代表该分区的根目录,chrome不允许这么做。

6.将一段代码加载在前台里执行

后台可以使用chrome.tabs.executeScript() API,它能在前台页面运行它里面的代码。

它的参数允许两种形式:

①.直接写代码:

chrome.tabs.executeScript({
	code: 'alert(1)';
});

②.调用一个外部文件:

chrome.tabs.executeScript({
	file: 'wosihjs.js';
});

其实这个方法的第一个参数是tab的id,不过是可选的,而且大部分时候不需要,所以我就没写。

代码会在前台页面执行,把它当成和content.js差不多的东西就行。

制作chrome扩展的一些经验