4.1 书签

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

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

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

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

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

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

"permissions": [
    "bookmarks"
]

在具体讲解操作书签的方法前,先让我们来了解一下书签对象的数据结构。书签对象有8个属性,分别是idparentIdindexurltitledateAddeddateGroupModifiedchildren。这8个属性并不是每个书签对象都具有的,比如书签分类,即一个文件夹,它就不具有url属性。index属性是这个书签在其父节点中的位置,它的值是从0开始的。children属性值是一个包含若干书签对象的数组。dateAddeddateGroupModified的值是自1970年1月1日至修改时间所经过的毫秒数。只有idtitle是书签对象必有的属性,其他的属性都是可选的。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个:parentIdindextitleurl,其他属性均不支持指定。如果不指定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);
});

移除书签。通过removeremoveTree可以删除书签,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包含parentIdindex属性,与所删除书签对象之前的属性相对应。

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

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

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

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

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

moveInfo包含parentIdindexoldParentIdoldIndex属性,与所移动书签对象移动前后的属性相对应。

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

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

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

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

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

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

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

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