本文将从个人经验出发,讲述为什么需要Chrome插件,如何开发,如何调试,到哪里找资料,会遇到怎样的问题以及如何解决等,同时给出一个个人认为的比较典型的例子——获取网页内容,和服务器交互,再把信息反馈给用户。OK,准备开始吧,我尽量把文章写得好看点,以免读者打瞌睡。 为什么需要 简单地说,浏览器插件,可以大大的扩展你的浏览器的功能。包括但不仅限于这些功能:捕捉特定网页的内容,捕捉HTTP报文,捕捉用户浏览动作,改变浏览器地址栏/起始页/书签/Tab等界面元素的行为,与别的站点通信,修改网页内容……给你增加许多想象空间,试想想看,你可以用它来识别一些网站上的广告代码,并直接把这些代码删掉,这样你就不会受到广告的困扰了,没错,如你所愿,这样的插件别人已经开发好了,你可以直接用。不过,也要说浏览器插件的弊端,那就是:会带来一些安全隐患,也可能让你的浏览器变得缓慢甚至不稳定。 为什么是Chrome 因为Chrome的插件开发起来最简单,总体上看没什么新的技术,开发语言就是javascript,web前端工程师能很快上手;而Firefox的插件开发则复杂许多,涉及到环境的搭建和一些WEB以外的技术;IE的插件开发就更复杂了,需要熟悉C++和COM技术,当然还要装微软的Visual Studio。 这里有篇老外写的文章,对比Chrome、Opera和Firefox的插件开发的:http://blog.nparashuram.com/2011/10/writing-browser-extensions-comparing.html。 应该说Chrome和Opera的插件的开发都不难,但Firefox的则比较棘手,也许你要问,那为什么Firefox的插件是最丰富的?我想这有些历史原因,Chrome出来毕竟比较晚,另外几种浏览器提供的插件的功能也是不尽相同的,OK,我们还是言归正传吧。 需要准备什么…
Chrome Extension : 事件交互实例 (消息传递, sendMessage,connect,onConnect,onMessage)
alert.js
alert('hello ' + document.location.href);
manifest.json
{ "manifest_version": 2, "name": "Click to execute", "description": "Execute script after click in popup.html (chrome extension) http://stackoverflow.com/questions/20764517/execute-script-after-click-in-popup-html-chrome-extension.", "version": "1.0", "icons": { "48": "icon.png" }, "permissions": [ "tabs", "<all_urls>" ], "browser_action": { "default_icon": "icon.png", "default_popup": "popup.html" }, "background": { "scripts": ["background.js"], "persistent": false } }
popup.html
<!DOCTYPE html> <html> <body style="width: 300px"> Open <a href="http://stackoverflow.com" target="_blank">this page</a> and then <button id="clickme">click me</button> <script type="text/javascript" src="popup.js"></script> </body> </html>
popup.js
// var app = chrome.runtime.getBackgroundPage(); function hello() { chrome.tabs.executeScript({ file: 'alert.js' }); } document.getElementById('clickme').addEventListener('click', hello);
GitHub:https://gist.github.com/greatghoul/8120275
简单的一次性请求
如果您只需要向您的扩展程序的另一部分发送一个简单消息(以及可选地获得回应),您应该使用比较简单的 runtime.sendMessage 方法。这些方法允许您从内容脚本向扩展程序发送可通过 JSON 序列化的消息,可选的 callback 参数允许您在需要的时候从另一边处理回应。
如下列代码所示从内容脚本中发送请求:
chrome.runtime.sendMessage({greeting: "您好"}, function(response) { console.log(response.farewell); });
从扩展程序向内容脚本发送请求与上面类似,唯一的区别是您需要指定发送至哪一个标签页。这一例子演示如何向选定标签页中的内容脚本发送消息。
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { chrome.tabs.sendMessage(tabs[0].id, {greeting: "您好"}, function(response) { console.log(response.farewell); }); });
在接收端,您需要设置一个 runtime.onMessage 事件监听器来处理消息。
chrome.runtime.onMessage.addListener( function(request, sender, sendResponse) { console.log(sender.tab ? "来自内容脚本:" + sender.tab.url : "来自扩展程序"); if (request.greeting == "您好") sendResponse({farewell: "再见"}); });
注意: 如果多个页面都监听 onMessage 事件,对于某一次事件只有第一次调用 sendResponse() 能成功发出回应,所有其他回应将被忽略。
长时间的连接
有时候需要长时间的对话,而不是一次请求和回应。在这种情况下,您可以使用runtime.connect 或 tabs.connect 从您的内容脚本建立到扩展程序的长时间连接。建立的通道可以有一个可选的名称,让您区分不同类型的连接。
使用长时间连接的一种可能的情形为自动填充表单的扩展程序。对于一次登录操作,内容脚本可以连接到扩展程序页面,每次页面上的输入元素需要填写表单数据时向扩展程序发送消息。共享的连接允许扩展程序保留来自内容脚本的不同消息之间的状态联系。
建立连接时,两端都将获得一个 runtime.Port 对象,用来通过建立的连接发送和接收消息。
如下代码演示如何从内容脚本中建立连接,发送并监听消息:
var port = chrome.runtime.connect({name: "敲门"}); port.postMessage({joke: "敲门"}); port.onMessage.addListener(function(msg) { if (msg.question == "是谁?") port.postMessage({answer: "女士"}); else if (msg.question == "哪位女士?") port.postMessage({answer: "Bovary 女士"}); });
为了处理传入连接,您需要设置一个 runtime.onConnect 事件监听器。这一步无论在内容脚本还是扩展程序页面中都是一样的。当您的扩展程序的另一部分调用 connect() 时,会产生这一事件,同时传递您可以通过建立的连接发送和接受消息的 runtime.Port 对象。如下代码演示如何回应传入连接:
chrome.runtime.onConnect.addListener(function(port) { console.assert(port.name == "敲门"); port.onMessage.addListener(function(msg) { if (msg.joke == "敲门") port.postMessage({question: "是谁?"}); else if (msg.answer == "女士") port.postMessage({question: "哪位女士?"}); else if (msg.answer == "Bovary 女士") port.postMessage({question: "我没听清楚。"}); }); });
您可能想知道连接何时关闭,例如您需要为每一个打开的端口单独保留状态。这种情况下您可以监听 runtime.Port.onDisconnect 事件,当连接的另一端调用 runtime.Port.disconnect 或包含该端口的页面已结束(例如标签页转到了另一个页面)时,对于每一个端口确保都会发生一次该事件。
更多有关消息传递:https://crxdoc-zh.appspot.com/apps/messaging
实例:
manifest.json
{ "manifest_version": 2, "name": "Click to execute", "description": "justcode.ikeepstudying.com", "version": "1.0", "icons": { "48": "icon.png" }, "permissions": [ "tabs", "<all_urls>" ], "browser_action": { "default_icon": "icon.png", "default_popup": "popup.html" }, "background": { "scripts": ["background.js"], "persistent": false } }
popup.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Popup</title> <style> *{font-family:"Microsoft Yahei","Monaco",sans-serif;font-size:13px;} button{cursor:pointer;padding:2px 4px 4px 4px;border:1px gray solid;background:none;} #wrapper{width:240px;height:120px;padding:0 12px;margin:auto;} #wrapper .clear{color: #fff;background-color: #d9534f;border-color:#d43f3a;} #waitingForClear{clear:both;display:inline-block;margin-top:4px;background:yellow;} </style> </head> <body> <div id="wrapper"> <p>Welcome to use Amazon Seller picker!</p> <button class="clear" id="clearCache">Clear All Sellers From Cache</button> <span id="waitingForClear"></span> </div> </body> <script type="text/javascript" src="scripts/popup.js"></script> </html>
popup.js等js文件最好写在最下方,否则操作内部html元素时,可能有无法获取元素的错误!
popup.js
var clearCacheBtn = document.getElementById("clearCache"); var waitingForClearAara = document.getElementById("waitingForClear"); // 简单一次性请求 // clearCacheBtn.addEventListener("click", function(e) { // waitingForClearAara.innerHTML("Clearing Cache, Please Waiting..."); // chrome.runtime.sendMessage({'clearAllCache': true}, function(response){ // waitingForClearAara.innerHTML("Clearing Cache, Please Waiting..."); // }); // }); // 长时间的连接 clearCacheBtn.addEventListener("click", function(e) { waitingForClearAara.innerHTML = "Clearing Cache, Please Waiting..."; var port = chrome.runtime.connect({name:"clearCache"}); port.postMessage({clearAllCache:true}); port.onMessage.addListener(function(response) { console.log(response); waitingForClearAara.innerHTML = (response.clearedAllCache ? "Cleared, Please Refresh Your Page To Load New Contents!" : "Fail To Clear Cache"); }); });
background.js
// 简单的一次性请求 // chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) { // if(message.clearAllCache) { // console.log("try to clear all cache ..."); // //console.log(sender.tab ? "来自内容脚本:" + sender.tab.url :"来自扩展程序"); // chrome.storage.local.clear(); // sendResponse({succes:true}); // } // else console.log("fail to clear cache..."); // }); // 长时间的连接 chrome.runtime.onConnect.addListener(function(port) { console.assert(port.name == "clearCache"); port.onMessage.addListener(function(message) { console.log(message); if (message.clearAllCache) { console.log("try to clear all cache ..."); chrome.storage.local.clear(); port.postMessage({clearedAllCache:true}); } }); });
更多参考:
Chrome 插件 DIY
如何查看chrome扩展的源代码, chrome扩展二次开发
文本:Chrome Extension : 事件交互实例 (sendMessage,connect,onConnect,onMessage)
Related Posts
- Chrome插件(Extensions)开发攻略
- Chrome 插件 DIY
1 前言 对于一个web前端开发者,chrome浏览器是一个工作,学习和生活的必备工具。除了chrome本身的基本能力(控制台等)外,能大幅提高这个神器的使用体验的是,可扩展能力(插件)以及丰富的插件生态。 每个人根据使用习惯会有自己的一套插件配置(鼠标手势、代理配置等等),这些插件包括具体的插件的配置信息,甚至可以和你的google账号绑定,当你换一台电脑,只要使用相同的google账号登录chrome,就会享受到一致的使用体验。 当你打开chrome的“扩展程序”界面,看着琳琅满目的插件,有没有想过亲自动手,打造一个自己的插件呢?当然,这种想法不应该是闲着某个部位疼,刻意的去开发一个连自己都不会实际使用的插件。而应该是发现现在的插件库里,没有一个能解决自已在使用chrome过程中某个痛点的插件。 好,假设现在你在chrome的使用上想要一个扩展功能,但用各种关键字在各种可能找到答案的地方都搜索了,仍然没有看到想要的插件。这个时候,就可以考虑自己开发了。如果刚好你是一个web前端开发者,那么恭喜你,几乎没有门槛(只要有能看懂chrome extentions API文档就行),因为所有用到的技术都是你所熟悉的: json配置,…
- Chrome Extension 学习笔记
要写Chrome Extension 的先决条件是拥有网页基础,因为写Chrome Extension 会用到HTML、Javascript、CSS,如果还不会这些东西,建议在学习Chrome Extension 之前,先把这些技能磨练好。 这篇介绍会针对Chrome Extension…
Related Posts

使用jQuery和Pure.CSS创建一个可编辑的表格

如何用 javascript 做一个高逼格的进度条
