陈建华的博客
专注web开发
【chrome扩展】管理你的浏览器(第四章)
2014-11-30 00:06:54   阅读5513次

前面介绍了Chrome扩展基础和UI界面,接下来我们来讲一讲有关管理浏览器的相关内容。本章将涉及到书签、Cookies、历史记录、扩展管理和标签有关的内容,通过本章的内容,你将能够创建功能更加强大的扩展。


4.1书签

书签这个功能在早期的浏览器就是标配了,浏览器在几十年的更新中,很多功能都已经被新的技术和方法替代,但书签这个功能一直保留至今,可见它对用户的重要程度。

在搜索引擎如此强大的今天,传统的书签已经不再拥有往日的优势,那么我们为什么现在还要保留和讨论这个功能呢?既然互联网索引从早期的人工编排(雅虎早期就是人工编排互联网黄页的)进化到了机器自动抓取并排序,那么书签这个古老的功能也没有理由止步不前。

说到了书签功能的进步,我们不妨来想一想哪些功能是现在书签所具有而曾经没有的。首先是同步,这个一定要放在第一位。当初多少人重新安装系统后望着浏览器空空如也的收藏夹(书签在原来的部分浏览器中也叫收藏夹)捶胸顿足,甚至当时把导出浏览器收藏夹都写入了重装系统的标配步骤中。现在我们再也不担心这个问题了,各大浏览器基本都支持了同步书签的功能,当然前提是你绑定了一个支持同步的账户。其次就是搜索功能,大家发现本来将页面放入书签是方便以后继续查看,但当书签数量变得庞大之后,这种方便也就无从谈起了,所以书签的搜索功能也就出现了。

在前面提到书签发展的进步并非与本节内容无关,这种进步会激发你的创造力,来想一想怎么通过下面将要讲解的浏览器书签管理接口打造更加智能的书签。

Chrome为开发者提供了添加、分类(书签文件夹)和排序等方法来操作书签,同时也提供了读取书签的方法。

要在扩展中操作书签,需要在Manifest中声明bookmarks权限:

"permissions": [
    "bookmarks"
]

在具体讲解操作书签的方法前,先让我们来了解一下书签对象的数据结构。书签对象有8个属性,分别是id、parentId、index、url、title、dateAdded、dateGroupModified和children。这8个属性并不是每个书签对象都具有的,比如书签分类,即一个文件夹,它就不具有url属性。index属性是这个书签在其父节点中的位置,它的值是从0开始的。children属性值是一个包含若干书签对象的数组。dateAdded和dateGroupModified的值是自1970年1月1日至修改时间所经过的毫秒数。只有id和title是书签对象必有的属性,其他的属性都是可选的。id不需要人为干预,它是由Chrome管理的。根的id为'0'。

创建书签。可以通过create方法来创建书签,下面的代码创建了一个标题为“Google”,URL为“

http://www.google.com/ ”的书签:
chrome.bookmarks.create({
    parentId: '1',
    index: 0,
    title: 'Google',
    url: 'http://www.google.com/'
}, function(bookmark){
    console.log(bookmark);
});

请注意上面代码的parentId属性,'0'为根节点id,根节点下是不允许创建书签和书签分组的,它的下面默认只有三个书签分组:书签栏、其他书签和移动设备书签,如果创建时不指定parentId,则所创建的书签会默认加入到其他书签中。create方法成功后会调用指定的回调函数,回调结果是书签对象。create方法支持指定的书签属性只有上述代码中所列出的4个:parentId、index、title和url,其他属性均不支持指定。如果不指定index,这个书签就将自动添加到相应父节点的尾部。

创建书签分类。创建书签分类的方法和创建书签的方法大致相同,如果创建的书签不包含url属性,则Chrome自动将其视作为书签分类。

调整书签位置。通过move方法可以调整书签的位置,这种调整可以是跨越父节点的,下面的代码将id为'16'的书签移动到了id为'7'的父节点第5个位置:

chrome.bookmarks.move('16', {
    parentId:'7',
    index:4
}, function(bookmark){
    console.log(bookmark);
});

更新书签。通过update方法可以更改书签属性,包括标题和URL,更新时未指定的属性值将不会更改。下面的代码将将id为'16'的书签标题改为'Gmail',URL改为'https://mail.google.com/':

chrome.bookmarks.update('16', {
    title: 'Gmail',
    url: 'https://mail.google.com/'
}, function(bookmark){
    console.log(bookmark);
});

移除书签。通过remove和removeTree可以删除书签,remove方法可以删除书签和空的书签分组,removeTree可以删除包含书签的书签分组。下面的代码移除了id为'16'的书签和id为'6'的书签分组。请注意,下面的代码实际上并不能看出删除的是书签还是分组,这要结合用户的实际情况。

chrome.bookmarks.remove('16', function(){
    console.log('Bookmark 16 has been removed.');
});
chrome.bookmarks.removeTree('6', function(){
    console.log('Bookmark group 6 has been removed.');
});

下面我们来了解一下如何获取用户的书签内容。通过getTree方法可以获得用户完整的书签树,但请注意,如果用户的书签树结构过于复杂或内容过多,getTree方法的效率会很低,而且也会消耗较多的资源,所以请考虑使用后面的方法按需获取部分书签树。下面的代码获取了用户的整个书签树:

chrome.bookmarks.getTree(function(bookmarkArray){
    console.log(bookmarkArray);
});

需要指出,上面的代码的返回结果依然是一个数组,虽然这个数组永远都只包含一个元素,书签树的根节点。

getChildren方法可以返回以指定节点为父节点的下一级书签节点,但不包括再下一级的节点,也就是说返回的书签对象不包括children属性,无论它是否具有子节点。通过这个方法我们可以一层一层地按需获取用户的书签结构。下面的方法获取了根节点的所有子节点。

chrome.bookmarks.getChildren('0', function(bookmarkArray){
    console.log(bookmarkArray);
});

getSubTree方法可以返回自指定节点开始包括当前节点及向下的所有节点,这个方法与getChildren的区别是返回值会包含父节点,且没有层级限制,即包含书签对象的children属性。下面的代码返回的结果与getTree方法返回的结果相同:

chrome.bookmarks.getSubTree('0', function(bookmarkArray){
    console.log(bookmarkArray);
});

get方法可以返回指定节点不包含children属性的书签对象数组,指定的节点可以是一个或多个。比如下面的代码获取了id为'16'和'17'的书签对象:

chrome.bookmarks.get(['16', '17'], function(bookmarkArray){
    console.log(bookmarkArray);
});

getRecent方法提供了获取最近添加的多个书签,下面的代码获取了最近添加的5个书签:

chrome.bookmarks.getRecent(5, function(bookmarkArray){
    console.log(bookmarkArray);
});

search方法可以返回匹配指定条件的书签对象,匹配的条件只能字符串,比如下面的代码会返回所有标题或URL中包含google的书签:

chrome.bookmarks.search('google', function(bookmarkArray){
    console.log(bookmarkArray);
});

最后我们来看一看书签的事件,Chrome提供了多个事件来监控书签操作行为。

onCreated事件用以监控书签的创建行为:

chrome.bookmarks.onCreated.addListener(function(bookmark){
    console.log(bookmark);
});

onRemoved事件用以监控书签的移除行为:

chrome.bookmarks.onRemoved.addListener(function(id, removeInfo){
    console.log('Bookmark '+id+' has been removed:');
    console.log(removeInfo);
});

removeInfo包含parentId和index属性,与所删除书签对象之前的属性相对应。

onChanged事件用以监控书签的更新行为:

chrome.bookmarks.onChanged.addListener(function(id, changeInfo){
    console.log('Bookmark '+id+' has been changed:');
    console.log(changeInfo);
});

changeInfo包含title和url属性,与所更改书签对象更新后的属性相对应。

onMoved事件用以监控书签的移动行为:

chrome.bookmarks.onMoved.addListener(function(id, moveInfo){
    console.log('Bookmark '+id+' has been moved:');
    console.log(moveInfo);
});

moveInfo包含parentId、index、oldParentId和oldIndex属性,与所移动书签对象移动前后的属性相对应。

onChildrenReordered事件用以监控一个书签分组下的更改子节点顺序的行为:

chrome.bookmarks.onChildrenReordered.addListener(function(id, reorderInfo){
    console.log('Bookmark '+id+' has a new children order:');
    console.log(reorderInfo);
});

reorderInfo是包含顺序更改后子节点id的数组。

onImportBegan和onImportEnded事件分别用以监控导入书签开始和结束的行为:

onImportBegan(function(){
    console.log('Bookmark import began.');
});
onImportEnded(function(){
    console.log('Bookmark import ended.');
});

请注意,如果检测到浏览器正在导入书签(onImportBegan事件被触发但onImportEnded事件还未被触发),应当忽略onCreated事件,但其他的操作可以被立即执行。

以上就是书签相关的全部内容,读者可以结合之前的内容创建更加智能方便的书签管理扩展。比如可以直接通过地址栏搜索书签,或者当用户使用Google搜索时将匹配到的书签结果添加到Google搜索结果的前端,类似Google广告推广那样。这些新奇的点子就交给读者们自行实现吧,在此就不给出实例了。

4.2Cookies

Cookies是浏览器记录在本地的用户数据,如用户的登录信息。Chrome为扩展提供了Cookies API用以管理Cookies。

要管理Cookies,需要在Manifest中声明cookies权限,同时也要声明所需管理Cookies所在的域:

"permissions": [
    "cookies",
    "*://*.google.com"
]

如果想要管理所有的Cookies可以声明如下权限:

"permissions": [
    "cookies",
    "<all_urls>"
]

请注意,除非必要,否则请不要如此声明权限,这会提示此扩展可以访问所有网络资源,给用户带来不安。

Chrome定义的Cookie对象包含如下属性:name(名称)、value(值)、domain(域)、hostOnly(是否只允许完全匹配domain的请求访问)、path(路径)、secure(是否只允许安全连接调用)、httpOnly(是否禁止客户端调用)、session(是否是session cookie)、expirationDate(过期时间)和storeId(包含此cookie的cookie store的id)。

读Cookies。Chrome提供了get和getAll两个方法读取Cookies,get方法可以读取指定name、url和storeId的Cookie,其中storeId可以不指定,但是name和url必须指定。如果在同一URL中包含多个name相同的Cookies,则会返回path最长的那个,如果有多个Cookies的path长度相同,则返回创建最早的那个。

chrome.cookies.get({
    url: 'https://github.com',
    name: 'dotcom_user'
}, function(cookie){
    console.log(cookie.value);
});

这里需要注意一点,如果cookie的secure属性值为true,那么通过get获取时url应该是https协议。

getAll方法与get方法不同,它可以获取所有符合条件的Cookies,支持的匹配条件包括url、name、domain、path、secure、session和storeId中的任意一个或多个,如果一个都不指定,则返回所有此扩展有权访问到的Cookies。比如下面的代码就可以获取到所有可以读取的Cookies:

chrome.cookies.getAll({}, function(cookies){
    console.log(cookies);
});

设置Cookie。set方法可以设置Cookie:

chrome.cookies.set({
    'url':'http://github.com/test_cookie',
    'name':'TEST',
    'value':'foo',
    'secure':false,
    'httpOnly':false
}, function(cookie){
    console.log(cookie);
});

如果创建成功,则回调函数会获取到创建后的cookie对象,否则会得到null。url是必须指定的,其他的属性可选。另外扩展对URL必须有访问权限,否则会设置失败。如果不指定expirationDate属性,则所创建的Cookie将在浏览器关闭后被删除。

01YwDeKDy9Bf.png

设置Cookies

删除Cookie。remove方法可以删除指定url、name和storeId的Cookie。

chrome.cookies.remove({
    url: 'http://www.google.com',
    name: '_ga'
}, function(result){
    console.log(result);
});

同样,扩展首先要具有对URL的访问权限,否则删除操作会失败。

除非你清楚在做什么,不要轻易删除用户的Cookies,否则你可能会收到大量用户抱怨气愤的邮件。

getAllCookieStores方法用来获取全部的cookie store,cookie store包含一个id属性和一个tabIds属性,id的属性值为这个cookie store的id,tabIds为包含共享这个cookie store所有tab的id的数组。有关tab的内容将在后面的章节讲解。

onChanged事件用来监控cookie的设置和删除行为:

chrome.cookies.onChanged.addListener(function(changeInfo){
    console.log(changeInfo);
});

changeInfo包含三个属性:removed,是否是删除行为;cookie,被设置或删除的cookie对象;cause,Cookie变化的原因,可能的值包括evicted、expired、explicit、expired_overwrite和overwrite。

再次提醒,Cookies是用户的敏感数据,在进行操作时一定倍加小心,并要让用户有知情权,必要时一定要先得到用户的确认。

4.3历史

历史用于记录用户访问过页面的信息。与书签一样,历史也是浏览器很早就具有的功能,对用户来说也是一个很重要的功能。Chrome提供了history接口,允许扩展对用户的历史进行管理。

要使用history接口,需要在Manifest中声明history权限:

"permissions": [
    "history"
]

管理历史的方法包括search、getVisits、addUrl、deleteUrl、deleteRange和deleteAll。其中search和getVisits用于读取历史,addUrl用于添加历史,deleteUrl、deleteRange和deleteAll用于删除历史。

读取历史。Chrome提供了search和getVisits两种方法读取历史。通过search方法可以读取匹配指定文字,指定时间区间,指定条目的历史结果。

chrome.history.search({
    text: 'Google',
    startTime: new Date().getTime()-24*3600*1000,
    endTime: new Date().getTime(),
    maxResults: 20
}, function(historyItemArray){
    console.log(historyItemArray);
});

上述代码会返回最近24小时内匹配“Google”的20条历史结果。startTime和endTime都是距1970年1月1日的毫秒数。返回结果是包含多个historyItem对象的数组,historyItem对象包含6个属性,分别是id、url、title、lastVisitTime、visitCount和typedCount,其中typedCount是用户通过在地址栏键入访问此历史的次数。若不指定text属性,则返回全部历史结果。

getVisits方法可以获取指定URL的访问结果。必须指定完整的URL,返回的结果会绝对匹配指定的URL,也就是说,如果指定'http://www.google.com/',返回的结果不会包含'http://www.google.com/a/'的内容。不要忘记http://,这也是不可省略的。

chrome.history.getVisits(
    url: 'http://www.google.com/'
}, function(visitItemArray){
    console.log(visitItemArray);
});

返回的结果是包含多个visitItem对象的数组,visitItem对象包含5个属性,分别是id、visitId、visitTime、referringVisitId和transition。其中id为与指定URL匹配的对象的id,对于匹配同一URL的对象拥有相同的id,visitId是这个访问结果的id,visitId是唯一的。visitTime同样是毫秒数。transition是此访问记录打开的方式,具体解释如下。

Chrome对每一个访问记录都详细地归类了打开方式,用transition属性记录。打开方式一共分为11种,这看起来确实会让人有一些头疼。比较常见的有四种,分别为link、typed、reload和form_submit。link是用户通过超级链接打开的方式,typed是用户通过在地址栏中输入网址打开的方式,reload是用户通过刷新(包括恢复关闭的标签)打开的方式,form_submit是通过提交表单打开的方式(通过脚本提交表单的情况不算此方式)。

与浏览器UI和设置相关的有两种,分别为auto_bookmark和auto_toplevel。auto_bookmark是通过浏览器UI中的建议打开的方式——比如通过菜单等。auto_toplevel为浏览器设置中默认打开的方式,比如浏览器的主页,或者是通过命令行启动时附带的参数。

嵌入式框架相关的有两个,auto_subframe和manual_subframe,其中auto_subframe为自动加载的嵌入式框架打开的方式,很多广告都是这样的打开方式——很多用户并不知道其实那些广告是在一个独立的页面中。manual_subframe则是用户手动加载的嵌入式框架打开的方式,比如用户操作商品菜单查看不同款式商品页面,就是手动加载嵌入式框架。

最后还有三种是和omnibox搜索建议相关的,分别为generated、keyword和keyword_generated。generated为通过omnibox给出搜索建议打开的方式,所打开的页面通常为搜索引擎的结果界面。keyword和keyword_generated都是通过用户在地址栏中输入的关键字生成的URL访问的方式,但其URL并不是默认搜索引擎生成的(否则就是generated了)。

添加历史。addUrl方法可以将特定的url以当前时间为访问时间,添加至历史中。

chrome.history.addUrl({
    url: 'http://twitter.com'
}, function(){
    console.log('Twitter has been added to history.');
});

删除历史。deleteUrl可以删除指定URL的历史,deleteRange可以删除指定时间段的历史,deleteAll可以删除全部历史。

chrome.history.deleteUrl({
    url: 'http://www.google.com'
}, function(){
    console.log('Google has been deleted from history.');
});
chrome.history.deleteRange({
    startTime: new Date().getTime()-24*3600*1000,
    endTime: new Date().getTime()
}, function(){
    console.log('History in past 24 hours has been deleted.');
});
chrome.history.deleteAll(function(){
    console.log('All history has been deleted.');
});

Chrome提供两个事件,onVisited和onVisitRemoved,分别监听用户访问历史和历史被删除的事件。

chrome.history.onVisited.addListener(function(historyItem){
    console.log(historyItem);
});
chrome.history.onVisitRemoved.addListener(function(removedObject){
    console.log(removedObject);
});

对于onVisitRemoved事件,返回的removedObject结果包含两个属性,allHistory和urls。其中urls属性包含所有被删除历史的URL。allHistory为布尔型,如果所有历史均被删除,allHistory的值为ture,同时urls的值会为一个空数组。

历史和cookies一样都是用户的敏感数据,进行操作时应让用户有知情权,尤其是要将用户历史数据与第三方共享时(包括开发者自己的服务器),一定要先得到用户的同意,并且要让用户得知哪些数据会被使用。

4.4管理扩展与应用

除了通过chrome://extensions/管理Chrome扩展和应用外,也可以通过Chrome的management接口管理。management接口可以获取用户已安装的扩展和应用信息,同时还可以卸载和禁用它们。通过management接口可以编写出智能管理扩展和应用的程序。

要使用management接口,需要在Manifest中声明management权限:

"permissions": [
    "management"
]

读取用户已安装扩展和应用的信息。Management提供了两个方法获取用户已安装扩展应用的信息,分别是getAll和get。

chrome.management.getAll(function(exInfoArray){
    console.log(exInfoArray);
});
chrome.management.get(exId, function(exInfo){
    console.log(exInfo);
});

exInfo是扩展信息对象,其结构如下:

{
    id: 扩展id,
    name: 扩展名称,
    shortName: 扩展短名称,
    description: 扩展描述,
    version: 扩展版本,
    mayDisable: 是否可被用户卸载或禁用,
    enabled: 是否已启用,
    disabledReason: 扩展被禁用原因,
    type: 类型,
    appLaunchUrl: 启动url,
    homepageUrl: 主页url,
    updateUrl: 更新url,
    offlineEnabled: 离线是否可用,
    optionsUrl: 选项页面url,
    icons: [{
        size: 图片尺寸,
        url: 图片URL
    }],
    permissions: 扩展权限,
    hostPermissions: 扩展有权限访问的host,
    installType: 扩展被安装的方式
}

其中type属性的可能值为extension、hosted_app、packaged_app、legacy_packaged_app或theme。installType可能的值为admin(管理员安装)、development(载入未打包的扩展)、normal(通过crx正常安装)、sideload(第三方程序安装)或other(其他)。

获取权限警告。getPermissionWarningsById和getPermissionWarningsByManifest方法可以获取权限警告,这些警告与用户安装扩展时网上应用商店弹出的警告类似。

chrome.management.getPermissionWarningsById(exId, function(permissionWarningArray){
    console.log(permissionWarningArray);
});
getPermissionWarningsByManifest(exManifest, function(permissionWarningArray){
    console.log(permissionWarningArray);
});

上述代码中,exManifest是字符串型的,不是对象型的。

启用、禁用、卸载扩展和启动应用。setEnabled方法可以启用或禁用扩展应用,如果一个扩展或应用被禁用,它的后台页面不会运行。

chrome.management.setEnabled(exId, enabled, function(){
    if(enabled){
        console.log('Extension '+exId+' has been enabled.');
    }
    else{
        console.log('Extension '+exId+' has been disabled.');
    }
});

卸载扩展有两种方法,uninstall可以卸载指定id的扩展,uninstallSelf可以卸载扩展自身且无需请求management权限。

uninstall(exId, {
    showConfirmDialog: true
}, function(){
    console.log('Extension '+exId+' has been uninstalled.');
});
uninstallSelf({
    showConfirmDialog: true
}, function(){
    console.log('This extension has been uninstalled.');
});

如果不希望在卸载前显示确认窗口,可以将showConfirmDialog的值设为false。

通过launchApp方法启动应用:

chrome.management.launchApp(exId, function(){
    console.log('App '+exId+' has been launched.');
});

management接口提供了四种事件,onInstalled、onUninstalled、onEnabled和onDisabled,分别用于监听安装、卸载、启用和禁用扩展应用。

chrome.management.onInstalled.addListener(function(exInfo){
    console.log('Extension '+exInfo.id+' has been installed.')
});
chrome.management.onUninstalled.addListener(function(exId){
    console.log('Extension '+exId+' has been uninstalled.');
});
chrome.management.onEnabled.addListener(function(exInfo){
    console.log('Extension '+exInfo.id+' has been enabled.');
});
chrome.management.onDisabled.addListener(function(exInfo){
    console.log('Extension '+exInfo.id+' has been disabled.');
});

本节讲解了管理扩展和应用的接口内容,看起来有些枯燥,但如果使用恰当设计合理,可以编写出让用户很feel的扩展。

4.5标签

前面的章节中,多次提到了标签,本节将详细讲解对标签信息获取和操作的内容。在开始介绍之前,先让我们来看一下标签对象的结构:

{
    id: 标签id,
    index: 标签在窗口中的位置,以0开始,
    windowId: 标签所在窗口的id,
    openerTabId: 打开此标签的标签id,
    highlighted: 是否被高亮显示,
    active: 是否是活动的,
    pinned: 是否被固定,
    url: 标签的URL,
    title: 标签的标题,
    favIconUrl: 标签favicon的URL,
    status :标签状态,loading或complete,
    incognito: 是否在隐身窗口中,
    width: 宽度,
    height: 高度,
    sessionId: 用于sessions API的唯一id
}

Chrome通过tabs方法提供了管理标签的方法与监听标签行为的事件,大多数方法与事件是无需声明特殊权限的,但有关标签的url、title和favIconUrl的操作(包括读取),都需要声明tabs权限。

"permissions": [
    "tabs"
]

获取标签信息。Chrome提供了三种获取标签信息的方法,分别是get、getCurrent和query。get方法可以获取到指定id的标签,getCurrent则获取运行的脚本本身所在的标签,query可以获取所有符合指定条件的标签。

chrome.tabs.get(tabId, function(tab){
    console.log(tab);
});
chrome.tabs.getCurrent(function(tab){
    console.log(tab);
});

query方法可以指定的匹配条件如下:

{
    active: 是否是活动的,
    pinned: 是否被固定,
    highlighted: 是否正被高亮显示,
    currentWindow: 是否在当前窗口,
    lastFocusedWindow: 是否是上一次选中的窗口,
    status: 状态,loading或complete,
    title: 标题,
    url: 所打开的url,
    windowId: 所在窗口的id,
    windowType: 窗口类型,normal、popup、panel或app,
    index: 窗口中的位置
}

下面的代码获取了所有在窗口中活动的标签:

chrome.tabs.query({
    active: true
}, function(tabArray){
    console.log(tabArray);
});

创建标签。创建标签与在浏览器中打开新的标签行为类似,但可以指定更加丰富的信息,如URL、窗口中的位置和活动状态等。

chrome.tabs.create({
    windowId: wId,
    index: 0,
    url: 'http://www.google.com',
    active: true,
    pinned: false,
    openerTabId: tId
}, function(tab){
    console.log(tab);
});

其中wId是创建标签所在窗口的id,如果不指定,则默认在当前窗口中打开。tId是打开此标签的标签id,可以不指定,但如果指定,那么所创建的标签必须与这个标签在同一窗口中。

除了用create方法,还可以使用duplicate方法“复制”指定标签:

chrome.tabs.duplicate(tabId, function(tab){
    console.log(tab);
});

更新标签。通过update方法可以更新标签的属性:

chrome.tabs.update(tabId, {
    url: 'http://www.google.com'
}, function(tab){
   console.log(tab);
});

更新标签时也可以不指定tabId,如果不指定,默认会更改当前窗口的活动标签。需要指出,直到31.0.1650.63 m,更新highlighted属性为true后,标签active属性也会被指定为true,所以如果只是想将某个标签高亮以引起用户的注意,需要先记录当前的标签id,更新后再将这个标签的active属性改回true。这个bug在之后的版本也许会被修正。

移动标签。move方法可以将指定的一个或多个标签移动到指定位置:

chrome.tabs.move(tabIds, {
    'windowId':wId,
    'index':0
}, function(tabs){
    console.log(tabs);
});

其中tabIds可以是一个数字型的标签id,也可以是一个包含多个标签id的数组。返回的tabs可能是标签对象也可能是包含多个标签对象的数组。如果指定的index为-1,会将标签移动到指定窗口的最后面。

重载标签。reload方法可以重载指定标签,同时还可以指定是否跳过缓存(强制刷新):

chrome.tabs.reload(tabId, {
    bypassCache: true
}, function(){
    console.log('The tab has been reloaded.');
});

浏览器通常会对一些静态资源进行缓存,JavaScript中的location.reload()方法通常无法实现强制刷新,此时上面的方法就会很好地解决这个问题。

移除标签。通过remove方法可以关闭一个或多个标签:

chrome.tabs.remove(tabIds, function(){
    console.log('The tabs has been closed.');
});

其中tabIds可以是一个数字型的标签id,也可以是一个包含多个标签id的数组。

获取当前标签页面的显示语言。有时可能需要针对用户浏览内容语言的不同,采用不同的处理方法。比如翻译扩展就要根据不同的语言决定是否提示用户进行翻译。

chrome.tabs.detectLanguage(tabId, function(lang){
    console.log('The primary language of the tab is '+lang);
});

如果不指定tabId,则返回当前窗口当前标签的语言。

获取指定窗口活动标签可见部分的截图。Chrome提供了截取指定窗口活动标签页面为图片的接口:

chrome.tabs.captureVisibleTab(windowId, {
    format: 'jpeg',
    quality: 50
}, function(dataUrl){
    window.open(dataUrl, 'tabCapture');
});

其中format还支持png,如果指定为png,则quality属性会被忽略。如果指定jpeg格式,quality的取值范围为0-100,数值越高,图片质量越好,体积也越大。扩展只有声明activeTab或<all_url>权限能获取到活动标签的截图:

"permissions": [
    "activeTab"
]

注入JS和CSS。之前我们接触过content_scripts,它可以向匹配条件的页面注入JS和CSS,但是却无法向用户指定的标签注入。通过executeScript和insertCSS可以做到向指定的标签注入脚本。

chrome.tabs.executeScript(tabId, {
    file: 'js/ex.js',
    allFrames: true,
    runAt: 'document_start'
}, function(resultArray){
    console.log(resultArray);
});

也可以直接注入代码:

chrome.tabs.executeScript(tabId, {
    code: 'document.body.style.backgroundColor="red"',
    allFrames: true,
    runAt: 'document_start'
}, function(resultArray){
    console.log(resultArray);
});

向指定的标签注入CSS:

chrome.tabs.insertCSS(tabId, {
    file: 'css/insert.css',
    allFrames: false,
    runAt: 'document_start'
}, function(){
    console.log('The css has been inserted.');
});

插入CSS也可以指定具体代码。

executeScript和insertCSS方法中runAt的值可以是'document_start'、'document_end'或'document_idle'。

与指定标签中的内容脚本(content script)通信。前面章节介绍过扩展页面间的通信,我们也可以与指定的标签通信,方法如下:

chrome.tabs.sendMessage(tabId, message, function(response){
    console.log(response);
});

请注意,后台页面主动与content_scripts通信需要使用chrome.tabs.sendMessage方法1。

1 chrome.tabs.executeScript方法也可以实现后台页面与内容脚本的通信,但更强调是后台页面向标签页注入脚本。

由于标签的操作行为比较多,所以相应的监视事件也很多。监控标签行为的事件包含onCreated、onUpdated、onMoved、onActivated、onHighlighted、onDetached、onAttached、onRemoved和onReplaced。

大部分事件都比较好理解,下面重点讲一讲不易理解的事件。onHighlighted是当标签被高亮显示时所触发的事件,active和highlight是有区别的,active是指标签在当前窗口中正被显示,highlight只是标签的颜色被显示成了白色——如果此标签没有被选中正常情况下是浅灰色。onDetached是当标签脱离窗口时所触发的事件,导致此事件触发的原因是用户在两个不同的窗口直接拖拽标签。onAttached是标签附着到窗口上时所触发的事件,同样是用户在两个不同的窗口直接拖拽标签导致的。onReplaced是当标签被其他标签替换时触发的事件2。

2 要解释清楚 onReplaced 就不得不提一下即搜即得和预呈现(Instant search, Prerendering)。例如默认搜索引擎为 Google,启用了即搜即得,网络条件也足够好,在打开的另一个网页地址栏中开始输入关键字并且即时出现结果时,此时按下回车键,当前标签页就会被 Google搜索结果替换,产生 onReplaced 事件。如果扩展程序通过 tabId 追踪标签页的话就必须处理该事件。

chrome.tabs.onCreated.addListener(function(tab){
    console.log(tab);
});
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab){
    console.log('Tab '+tabId+' has been changed with these options:');
    console.log(changeInfo);
});
chrome.tabs.onMoved.addListener(function(tabId, moveInfo){
    console.log('Tab '+tabId+' has been moved:');
    console.log(moveInfo);
});
chrome.tabs.onActivated.addListener(function(activeInfo){
    console.log('Tab '+activeInfo.tabId+' in window '+activeInfo.windowId+' is active now.');
});
chrome.tabs.onHighlighted.addListener(function(highlightInfo){
    console.log('Tab '+activeInfo.tabId+' in window '+activeInfo.windowId+' is highlighted now.');
});
chrome.tabs.onDetached.addListener(function(tabId, detachInfo){
    console.log('Tab '+tabId+' in window '+detachInfo.oldWindowId+' at position '+detachInfo.oldPosition+' has been detached.');
});
chrome.tabs.onAttached.addListener(function(tabId, attachInfo){
    console.log('Tab '+tabId+' has been attached to window '+detachInfo.newWindowId+' at position '+detachInfo.newPosition+' .');
});
chrome.tabs.onRemoved.addListener(function(tabId, removeInfo){
    console.log('Tab '+tabId+' in window '+removeInfo.windowId+', and the window is '+(removeInfo.isWindowClosing?'closed.':'open.'));
});
chrome.tabs.onReplaced.addListener(function(addedTabId, removedTabId){
    console.log('Tab '+removedTabId+' has been replaced by tab '+addedTabId+'.');
);

通过标签接口,扩展可以更灵活地处理不同标签。虽然标签涉及到的内容很多,但常用的部分很有限,读者在阅读此节时,不妨先把精力重点放在那些常用易懂的方法事件上,对于剩下的部分随用随查即可。

4.6Override Pages

Chrome不仅提供了管理书签、历史和标签的接口,还支持用自定义的页面替换Chrome相应默认的页面,这就是override pages。目前支持替换的页面包含Chrome的书签页面、历史记录和新标签页面。

使用override pages很简单,只需在Manifest中进行声明即可(一个扩展只能替换一个页面):

"chrome_url_overrides" : {
    "bookmarks": "bookmarks.html"
}
"chrome_url_overrides" : {
    "history": "history.html"
}
"chrome_url_overrides" : {
    "newtab": "newtab.html"
}

把上面页面的地址替换成你自己的就可以了。

Google官方对override pages给出了几点建议(以下内容翻译来自https://crxdoc-zh.appspot.com/extensions/override):

使您的页面又快又小。
用户期望内置的浏览器页面能够立即打开。请避免做任何可能花较长时间的事情,例如,避免同步地获取网络或数据库资源。

在您的页面中包含标题。
否则用户可能会看到页面的 URL,会令人感到疑惑。这是一个指定标题的例子:新标签页

不要假定页面具有键盘焦点。
当用户创建新标签页时总是地址栏先获得焦点。

不要试着模仿默认的“打开新的标签页”页面。
用于创建与默认的“打开新的标签页”页面类似(具有最常访问的网站、最近关闭的标签页、提示、主题背景图像等等)的修改版本所需的 API 还不存在。在出现那些 API 之前您还是最好还是考虑一些完全不同的新想法。




-----------------------------------------------------
转载请注明来源此处
原地址:#

-----网友评论----
暂无评论
-----发表评论----
微网聚博客乐园 ©2014 blog.mn886.net 鲁ICP备14012923号   网站导航