4.5 标签
前面的章节中,多次提到了标签,本节将详细讲解对标签信息获取和操作的内容。在开始介绍之前,先让我们来看一下标签对象的结构:
{
id: 标签id,
index: 标签在窗口中的位置,以0开始,
windowId: 标签所在窗口的id,
openerTabId: 打开此标签的标签id,
highlighted: 是否被高亮显示,
active: 是否是活动的,
pinned: 是否被固定,
url: 标签的URL,
title: 标签的标题,
favIconUrl: 标签favicon的URL,
status :标签状态,loading或complete,
incognito: 是否在隐身窗口中,
宽度,
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+'.');
);
通过标签接口,扩展可以更灵活地处理不同标签。虽然标签涉及到的内容很多,但常用的部分很有限,读者在阅读此节时,不妨先把精力重点放在那些常用易懂的方法事件上,对于剩下的部分随用随查即可。