转载:http://www.cnblogs.com/walkingp/archive/2011/04/04/2003875.html
手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单
Chrome的更新速度可以说前无古人,现在我每天开机的第一件事就是打开Chrome检查是不是有了新版本。界面清爽、操作人性化、网络备份资料和快速的启动速度令我爱不释手,还有它拥有众多的扩展程序,相对于firefox的插件来说,数量上和质量上稍显不足,但相信chrome将会很快在扩展上超越firefox,firefox上内存占用上实在不令人满意,也许我使用firefox的一个原因就是因为firebug,不过相信chrome平台的类firebug插件也会很快出现。
Chrome的扩展开发十分简单,我们只需要掌握web开发的htm+CSS+Javascript,就能很快开发出自己的扩展。
你需要了解的内容
在开发前首先要掌握一些基础知识。
1、Chrome扩展文件
Chrome扩展文件以.crx为后缀名,在Google Chrome扩展官方网站下载扩展时,Chrome会将.crx文件下载到Chrome的Application Data文件夹的User DataTemp下,一般是C:Documents and SettingsUserLocal SettingsApplication DataGoogleChromeUser DataTemp,安装完成或者取消安装,该文件就会被删除。.crx实际上是一个压缩文件,使用解压文件打开这个文件就可以看到其中的文件目录,下图中是“关灯看视频”扩展的截图:

因此可以认为,我们实际上就是写一个Web应用,然后将按照Chrome的规定将一个快捷方式放在Chrome工具栏上。
2、Browser Actions(扩展图标)
把Browser Actions翻译成扩展图标不是很准确,但它的功能就是把你的应用显示在Chrome工具栏上。我们在上面看到一个文件manifest.json,就是使用这个文件来把相应的图标和其他参数注册到Browser Actions。比如下图中就是EverNote的扩展图标。

3、Page Actions(地址栏图标)
如果你熟悉一些Chrome插件的话,你一定会发现有些扩展的图标不是显示在地址栏的右边,而是显示在地址内部右方,这就是Page Actions地址栏图标。

可以看出上面中有三个Page Actions,图中我标出的是Chrome添加书签,现在你就会发现其实这个也是Chrome的扩展,只不是它是直接内置在Chrome的。
Page Actions与Browser Actions的区别就是Page Actions不是随时都是显示的,必须在特定的页面中这个功能才能使用。因此在开发中注意:如果不是全部页面中都能使用的功能请使用Page Actions方式。
4、popup弹出窗口
popup属于Browser Actions,当点击图标时出现这个窗口,可以在里面放置任何html元素,它的宽度是自适应的。当然,这个弹出窗口不会被Chrome拦截的:)
如下图中是evernote的popup窗口:

5、Background Pages后台页面
这个窗口不会显示,它是扩展程序的后台服务,它会一直保持运行。比如在一些需要数据保存程序中,如果当前用户关闭popup,就需要Background Pages来进行相应的操作。
自己动手做一个
我们以一个简单的任务管理程序来一步步讲解。

上图是界面实现,我们首先完成界面的显示部分,首先建立一个新文件夹,以扩展应用的名称为标题,我们这里的应用叫做MyTaskList。然后把找一个图标文件,放到文件夹中,也可直接右键下载我的这个图标:

图标文件不要小于19px*19px,但最好也不要超过这个尺寸,虽然大图它会自适应,但会使得应用文件变大。然后完成和未完成状态的两个图标放到资源文件中,可以建立任意文件夹放进去,因为CSS文件把定义它们的路径。
建立manifest.json来定义我们程序配置:
{ "name": "MyTaskList", "version": "0.9.0", "description": "Management my everyday's task lists.", "browser_action": { "default_icon": "icon.png" , "default_title": "My Task List", "default_popup": "popup.html" } } |
其中name代表应用程序名,version代表版本号,description代表功能描述。这些在安装扩展后就能看到,见下图:

browser_action代表扩展图标段显示,它会定义图标地址、标题(也就是鼠标悬停提示)和默认的popup页面。我们这里定义的popup页面为popup.html。
接下来开始定义popup.html显示,它不需要使用<html>、<head>和<body>标签,可以直接写上样式、脚本和html。我们的popup.html源码为:
<style type="text/css">*{margin:0;padding:0;}body{color:#333;overflow: hidden;margin: 0px;padding:5px;background: white;font-size:12px;}img{margin:0 4px;}#addItemDiv{color:#ccc;}.hide{display:none;}.show{display:block;}.taskItem{cursor:pointer;}input{100%;}label.on{12px; display:inline-block; height:12px; background:url(images/bg_task_on.gif) no-repeat 0px 2px;}label.off{12px; display:inline-block; height:12px; background:url(images/bg_task_off.gif) no-repeat 0px 2px;}</style><div id="newItem" class="gray">添加新项</div><div id="addDiv" class="hide"><input type="text" id="txtTitle" /></div><div id="taskItemList"> <div class="taskItem"> <label class="on"></label><span class="taskTitle">新任务</span> </div> <div class="taskItem"> <label class="off"></label><span class="taskTitle">已完成任务</span> </div></div> |
打开预览,样子就已经出来了:

这样我们文件就已经建立完成,文件列表如下:

现在就可以先尝试把它打包装到自己的Chrome里。
首先打开Chrome-工具-扩展程序,展开开发人员模式,打到“打包扩展程序”按钮:

点击“打包扩展程序…”,弹出打包选择文件窗口,在扩展程序根目标中找到我们建立的文件夹,私有密码文件第一次不用选择:

点击确定,它会在根文件夹同一级生成MyTaskList.crx和MyTaskList.pem,MyTaskList.pem是程序签名文件,以新版本的开发中还需要这个文件,不要删除它。把MyTaskList.crx拖进Chrome窗体内,就会把这个应用MyTaskList安装在Chrome里。

我们的这个简单的模型就能看到效果了,下一节我们就会完善其中的代码。
上一节我们已经讲了Chrome扩展的基础知识,并构建了基础的html,这一节我们将就html DOM添加部分添加脚本,即脚本在我们的popup页面中进行的操作,页面所产生的变化。
正常情况下数据处理加载完成状态,这些数据是从本地数据读取的。

点击“添加新项”,出现输入框,输入文字后回车提交数据:

添加完成后将数据存储,同时添加DOM元素:

考虑到功能最简化处理,点击已标为完成的任务,将提示“删除或重置为未完成”:

以上功能为最核心功能,可以在此基础上进行扩展,比如任务分组,修改任务,任务提醒,网络同步数据等等。
下面开始相应的脚本内容。
为了避免全局变量,使用匿名函数方式,所有事件处理及数据绑定均在此函数中进行,同时定义与jQuery中的$()类似的函数:
(function(){ var $=function(id){return document.getElementById(id);}})(); |
建立Tasks对象,定义show()函数和hide()函数,同时存储几个常用的DOM对象。
var Tasks = { show:function(obj){ obj.className=''; return this; }, hide:function(obj){ obj.className='hide'; return this; }, //存储dom $addItemDiv:$('addItemDiv'), $addItemInput:$('addItemInput'), $txtTaskTitle:$('txtTaskTitle'), $taskItemList:$('taskItemList')} |
其中show()函数和hide()函数均使用了链式调用,每次执行此函数均会返回对象本身,这样对象就可以使用形如类似jQuery书写方式来使用此函数。
然后注册事件:
//.....//初始化init:function(){ /*注册事件*/ //打开添加文本框 Tasks.$addItemDiv.addEventListener('click',function(){ Tasks.show(Tasks.$addItemInput).hide(Tasks.$addItemDiv); Tasks.$txtTaskTitle.focus(); },true); //回车添加 Tasks.$txtTaskTitle.addEventListener('keyup',function(ev){ var ev=ev || window.event; if(ev.keyCode==13){ //TODO:写入本地数据 Tasks.AppendHtml(task); Tasks.$txtTaskTitle.value=''; Tasks.hide(Tasks.$addItemInput).show(Tasks.$addItemDiv); } ev.preventDefault(); },true); //取消 Tasks.$txtTaskTitle.addEventListener('blur',function(){ Tasks.$txtTaskTitle.value=''; Tasks.hide(Tasks.$addItemInput).show(Tasks.$addItemDiv); },true); //TODO:初始化数据,加载本地数据,生成html },//.... |
其中待完成部分为我们下一节将重点计到的html5的本地存储功能。再定义数据操作部分,先写上空白函数:
//....//增加Add:function(){ //TODO},//修改Edit:function(){ //TODO},//删除Del:function(){ //TODO},//... |
还需要初始化此函数使其执行并让匿名函数执行:
(function(){ var Tasks = {//*** } Tasks.init();})(); |
好吧,以下就是本节中所要提到的全部代码:
代码中尚未实现的部分,我们将会在下节详细讲解其实现。
HTML5中的localStorage
localStorage与cookie类似,它是存储在客户端浏览器中的数据,它与cookie不同的一点是它没有时间限制。localStorage属于html5中的新特性,在浏览器支持localStorage统计中,Chrome4+、Firefox3.5+、IE8+、IE7兼容模式、Safari4+、Opera10.5+都是支持localStorage的。以下代码可以用于检测你的浏览器是否支持localStorage:
if(window.localStorage){ alert('你的浏览器支持localStorage!');}else{ alert('浏览器不支持localStorage!');} |
localStorage是以key/value方式来进行存储的,并且value只能是字符串形式,如果你要使用其他数据类型,需要进行相应的转换。设置和获取localStorage方法是使用localStorage.key,或localStorage[key]的形式,如:
localStorage.myName='walkingp';localStorage['mySite']='http://www.cnblogs.com/walkingp';alert('name:' + localStorage.myName + '
site:' + localStorage['mySite']); |
修改其值就是重新设置相应的localStorage项取值。移除其值可以将其值设为null。
localStorage['mySite']=null; |
也可以使用localStorage自带方法getItem()、setItem()和removeItem()来进行相应的获取、设置和移除localStorage项。
localStorage.setItem('age','24');var age=localStorage.getItem('age');alert('age:' + age);//age:24localStorage.removeItem('age');age=localStorage.getItem('age');alert('age? ' + age);//age? null |
可以使用clear()方法来清空所有localStorage。
对于不同域的localStorage,如本地和a.com,两者不影响对方。
关于localStorage本地存储大小,有人测试结果是其他浏览器为5M,Firefox没有作限制。而cookie一般只有几K,可见localStorage非常适合做稍大一些的数据存储,当然对于Chrome等扩展开发是非常合适的。
浏览器中的localStorage管理工具
Chrome和Safari均有自己的本地localStorage查看和管理工具,Firefox拥有第三方插件可以管理localStorage,Chrome中位于开发人员工具中的Resources左侧的Databases(可能稍早一点的版本位于单独出来的工具栏)。我们上面的localStorage在Chrome查看如下,利用这个工具可以修改或者删除相应项。

Safari中需要先在“偏好设置”、“高级”中将“在菜单中显示开发选项”勾选。

开始存储我们的localStorage
以上是我们需要了解的关于localStorage的知识,接下来就是把这个知识应用到我们Chrome扩展中。我们的数据存储分为两个部分,一是每项task需要存储的内容,它是以JSON的形式来存储的,形式如下:
task1:{"id":1,"task_item":"新任务","add_time":"2011-04-04T03:20:34.879Z","is_finished":false} |
task1表示key项,后台的JSON表示value项。意义很简单明了,其中is_finished表示当前任务是否已完成。当更新任务状态时就是将此项取值进行相应的更改。
还要放一个指向当前任务的数据,让它充当指针的作用,这样在添加新项时就不需要查询已有task项的id了。
'Tasks:index':1 |
下面是我们代码的具体实现,首先开始初始化数据:
var Tasks = { //指针 index:window.localStorage.getItem('Tasks:index'), //初始化 init:function(){ if(!Tasks.index){ window.localStorage.setItem('Tasks:index',Tasks.index=0); } //初始化数据 if(window.localStorage.length-1){ var task_list=[]; var key; for(var i=0,len=window.localStorage.length;i<len;i++){ key=window.localStorage.key(i); if(/task:d+/.test(key)){ task_list.push(JSON.parse(window.localStorage.getItem(key))); } } for(var i=0,len=task_list.length;i<len;i++){ Tasks.AppendHtml(task_list[i]); } } },//***} |
然后是分别是增加项Add()、修改项Edit()和删除项Del()的方法:
//增加Add:function(task){ //更新指针 window.localStorage.setItem('Tasks:index', ++Tasks.index); task.id=Tasks.index; window.localStorage.setItem("task:"+ Tasks.index, JSON.stringify(task));},//修改Edit:function(task){ window.localStorage.setItem("task:"+ task.id, JSON.stringify(task));},//删除Del:function(task){ window.localStorage.removeItem("task:"+ task.id);},//*** |
其中的JSON.stringify是JSON将Javascript数据结构转换为JSON文本的方法,它与eval()为互操作。详情可见http://json.org/js.html 。
这样我们就将一个简单的Chrome扩展完成了,演示效果图如下:

当然它现在的功能还不够强大,我们还可以对它进行继续扩展,比如任务排序、任务分组、网络存储、定时提醒等。
系列文章至此暂时结束,全部代码包括生成后.crx文件已经打包,下载请点击此处。可能已有代码有一些处理不完善的地方,欢迎大家一一指出,共同进步!
报错:RSEM can not recognize reference sequence name chr1!(基因组的bam不能直接用rsem进行表达值计算)
R: 使用tapply根据相同ID合并指定列
linux:去除特定列为空格的行
知乎一答:程序员为什么要关注管理
如何掌握一门编程语言的运用
谈谈程序员这个职业及前景
Oracle学习笔记(2)--Centos 7 下11gR2部署
用flask写一个简单的接口
iptables命令详解
- 最新文章
-
mysql binlog
freemarker代码生成
Orika 对象复制 克隆
mysql 字段长度 字符 字节
Spring 事务失效的 12 种场景
java stream 流操作 一些示例2
IDEA REST Client
使用Docker 安装配置Zabbix 监控,实现局域网主机监控告警
flv.js播放视频时出现Failed to execute ‘appendBuffer’ on ‘SourceBuffer’ 错误
PostgreSQL远程连接,发生致命错误:没有用于主机“…”,用户“…”,数据库“…”,SSL关闭的pg_hba.conf记录
- 热门文章
-
pip install keras_常用基本pip命令及报错问题解决(不断更新)
pyinstaller 打包 keras tensorflow pyqt 的 打包步骤(踩坑日记 )
TensorFlow安装常见问题和解决办法
数学建模部分算法整理
sklearn中cross_val_score、cross_val_predict的用法比较
R语言:使用 as.numeric 转为数字型时建议加上as.character
本周最新文献速递20211010
R语言:windows下保存为pdf, png等文件名不能出现冒号":"
本周最新文献速递20211003
蛋白质组学/生物信息学博士后、研究助理招聘:深圳湾实验室系统与物理生物学研究所化学蛋白质组学课题组招聘