本文略微记录一下开发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差不多的东西就行。
saber酱是做什么工作的?前端?
有点好奇=w=
要是冒犯了请多包涵……