Web应用中的离线数据存储,时间流互联网之未来

Facebook 引发的 HTML5 危机

2012/09/01 · HTML5 · 来源:
@AppCan 刘鑫     ·
HTML5

作者:AppCan 刘鑫

近期几个新闻堆叠在一起,颇有韵味。先是 WHATWG 和 W3C 在 HTML5
标准上分道扬镳,继而“Facebook
移动应用宣布放弃 HTML5 的部分,改为纯 Native
方式开发”,接着又传闻苹果 AppStore
肃杀基于 Web 技术的
App。这几个事件对移动互联网行业来说个个都是重磅炸弹,押注 HTML5
的受到不小的打击,唱衰 HTML5
发展的借此幸灾乐祸。HTML5真的只是一场政治斗争吗?到底 Facebook
为什么放弃 HTML5?现阶段 HTML5 到底出了什么问题?

Facebook 放弃 HTML5 主因:慢

“对于 Facebook 的 iOS
原生应用来说,它主要在三个方面有很大的速度提升:应用启动、共享新闻滚动还有图片点击查看。其总体速度大约提升了一倍。这个版本部分采用了
Facebook Camera 和 Facebook Messenger
两款应用的代码库:其中图片点击查看功能的代码是从 Facebook Camera
移植过来,而屏幕消息是从 Facebook Messenger
那克隆过来的。这个原生版本是由一个独立的团队开发,产品经理 Johnson
表示未来会充分利用公司的代码共享,也会适当向其他团队寻求帮助。”

上述摘自 Facebook 的官方博客。博客中介绍到 Facebook 的 iOS 原生应用放弃
HTML5
后速度得到大幅度提升。大家不禁好奇,为什么
HTML5 会比原生 NativeApp 要“慢”很多?

在当前的移动终端设备硬件配置和操作系统优化水平的前提下,大部分基于 HTML5
开发的 Web
页面会出现延时加载展示的现象,也就是俗称的卡、慢。特别是在不同的视图界面(view)切换之间,这种卡和不流畅的现象会尤为严重。而
Native 应用不会出现这种情况。究其根源,在于浏览器解析的运作机制和原生
Native 的界面展示机制差异上。如下图所示:

 图片 1

红色框起来的部分是原生 NativeApp 的界面展示机制,简单的看起来就是 1
个步骤 ——
展示,因为所有的绘图和渲染工作都由系统直接完成。而红框以外的部分包括红框内的部分是
webkit 核心的浏览器解析页面的流程。相比 Native 的 1 个步骤,webkit
的解析过程可谓漫长而艰辛。历经解析、建立 Dom
树、获取对应资源、布局、建立渲染树、绘图到展示。所以不管移动终端设备硬件如何发展,这个差异是始终存在的,最多只是随着硬件的提升和软件的优化将这个差异收缩到最小甚至忽略。

更糟糕的是。Facebook 之前的 iOS 混合了 HTML5 的移动应用,使用 HTML5
绘图的页面在 HTML5 开发上也毫无技巧可言,基本沿用了主流前端开发框架
jQuery mobile 等的单 View 多 div
的机制。也就是在一个网页内绘制多个视图,页面之间的切换其实只是一个页面内不同区块的切换。这种方式加大了浏览器的渲染和绘制工作强度。并且在数据加载和流量上产生很大的负面影响。如果切换到新页面,之前的页面不进行销毁,则会加大运算量和增加内存占有,而如果销毁又会导致已经下载的数据失效,要重新载入,浪费流量。类似情况在中国的网络和设备情况下会尤为突出。所以
Facebook 不当的在 Native App 内混搭 HTML5 也难免引来用户怨言。

还有,一如报道中提到的,Facebook
这次的改进提升主要是“新闻滚动和图片点击”。如果了解 HTML5
的人,就会发现,这两点当然是“不应该在现阶段使用 HTML5
实现的”。为什么?笔者作为一个基于 HTML5 技术的 Hybrid App
系统的设计者,设计秉承的一个原则就是“凡是需要’动’的部分和需要大量运算的部分,就最好使用原生弥补,而不是一定要使用
HTML5 来实现”。新闻滚动,这种不停通过改变 Dom
树近而改变渲染再绘图展示的使用场景相比原生 Native
弱势是非常明显的。至于图片的部分就更不用多说了,这并不是 HTML5
眼下擅长的部分。HTML5
现在擅长的部分是数据量不大的页面、动画少的页面,特别是跨平台的开发。充分利用好
HTML5 的优势,尽量降低 HTML5 的弱势,学会用好
HTML5,才是现在这个时期使用 HTML5 开发的重点。可以说开发技巧很重要。

现阶段 HTML5 的问题:政治斗争

图片 2

“原生版本是一个独立团队开发的。”Facebook
公开的这一点也耐人寻味。原来客户端是 Native 与 HTML5
混合的方式,原来的团队也肯定有原生的开发能力,为什么非要一个独立团队重新耗费
6 个月进行重新开发?或许这里不能排除公司内政治因素,而 HTML5
成为一个牺牲品。HTML5
的政治不仅是一个公司内的,更是整个行业的。7月份,同为 HTML5 制定者的
WHATWG 和 W3C
表示无法继续合作,前者希望制定一个能够跟随市场或技术动态的标准;后者则要确立一个“死”的标准,一旦正式颁布再也无法修改。

WHATWG 和 W3C 的分道扬镳或许会成为 HTML5 发展的一个分水岭。WHATWG 背后有
Google、苹果,W3C
拉到了特立独行的巨无霸微软。标准是为利益服务的,曾经力推 HTML5
的苹果,现在也传闻在 AppStore 内打压基于 HTML5 开发的
App。那苹果到底是喜欢还是不喜欢
HTML5?喜欢也是真,讨厌也是真。过去乔布斯为了灭掉 Adobe 的 Flash,将
HTML5 当成冲锋枪,在移动端干掉了 Flash
之后,面对自己封闭生态系统的巨大利益和 HTML5
世界大同的愿景做出选择的时候,苹果当然毫无悬念的选择自己的利益。

《Web App
的挑战(三):入口之争》一文中,我有阐述自己的观点:入口之争”在现有移动操作系统设计架构下,浏览器很难和用户桌面争夺核心入口地位。苹果打造的
iOS 系统就是一个应用优先的系统,无论 HTML5 怎么发展,Web App
如何挣扎,浏览器如何砸钱,都抢不过用户桌面的入口地位。基于 HTML5 的 Web
App 的命运被苹果牢牢把控。Android 系统这个跟随 iOS
桌面入口理念的半山寨货也没有押注 Web App 而是将这个任务交给了 Chrome
OS。所以,不用炒概念,也不用谈未来,用 HTML5
开发原生应用,而不是仅仅套个外壳那么简单才是现阶段 HTML5
使用的重点和发展的重点。并且苹果封杀的也只是纯 HTML5 套壳的
App,对于使用混搭模式(包括 Facebook
之前的版本)的移动应用还是保持开放姿态,毕竟这种 HTML5
还是在苹果的生态系统内可控的运行着。

最后

Facebook 的 iOS 放弃
HTML5。幸灾乐祸也好,沮丧也罢。变的只是一个应用,HTML5
的势头和趋势不是一个企业可以逆转的。现阶段,真正的了解 HTML5,掌握 HTML5
的开发技巧和在恰当的地方用好 HTML5,才是把握机遇的重点。

 

 

 

赞 收藏
评论

图片 3

时间流互联网之未来(下)

2013/04/15 · HTML5 · 1
评论 ·
HTML5

来源:pingwest

总结

可以看见,在Web应用中使用离线数据并不是十分复杂。希望通过阅读这篇文章,各位能够在Web应用中加入离线数据的功能,使得你们的应用更加友好易用。你可以在这里下载所有的源码,尝试一下,或者修修改改,或者用在你们的应用中。

赞 收藏
评论

《时间流互联网之未来(上)》

LocalStorage和SessionStorage

如果你想在Javascript代码里面保存些数据,那么这两个东西就派上用场了。前一个可以保存数据,永远不会过期(expire)。只要是相同的域和端口,所有的页面中都能访问到通过LocalStorage保存的数据。举个简单的例子,你可以用它来保存用户设置,用户可以把他的个人喜好保存在当前使用的电脑上,以后打开应用的时候能够直接加载。后者也能保存数据,但是一旦关闭浏览器窗口(译者注:浏览器窗口,window,如果是多tab浏览器,则此处指代tab)就失效了。而且这些数据不能在不同的浏览器窗口之间共享,即使是在不同的窗口中访问同一个Web应用的其它页面。

旁注:有一点需要提醒的是,LocalStorage和SessionStorage里面只能保存基本类型的数据,也就是字符串和数字类型。其它所有的数据可以通过各自的toString()方法转化后保存。如果你想保存一个对象,则需要使用JSON.stringfy方法。(如果这个对象是一个类,你可以复写它默认的toString()方法,这个方法会自动被调用)。

Facebook Home、HTC BlinkFeed功能、SO.HO……

Facebook 发布了一款基于Android 的深度应用 Facebook
Home,到现在国内外仍不乏许多媒体称赞Mark
Zuckerberg的明智之举。虽然我不认为Facebook
Home称得起如此大的赞誉,但它却实实在在地可以说是互联网时间流形态很好的例子。本文除了介绍Facebook
Home ,还会介绍HTC
Sence UI的BlinkFeed、第三方应用SO.HO 以及和互联网时间流理论类似的简单演示 lifestreams.com等。

图片 4

Facebook Home

关于Facebook Home
,PingWest之前的几篇文章有过介绍。它是一款Android手机深度定制App,相当于在应用层和系统层中间加了一层。用户的直接使用感受就是:你的Facebook
好友图片信息流都会在主屏幕显示,你可以滑动桌面浏览Facebook好友照片;当有短信、消息或Facebook
Message时,可以直接在主屏幕上进行回复、删除、存档等操作;与Facebook好友聊天也可以指直接在桌面上进行;另外Facebook
Home的 Launcher允许用户选取几个最常用的进行快速打开或使用。

可以看出,Facebook已经把互联网信息流(只有Facebook内容)直接推到用户的主屏幕上了,用户每时每刻都在浏览Facebook上的信息,而Facebook
的Newsfeed恰恰又是一时间流的形式排序的,所以这是一个非常典型的互联网时间流应用形式。

但互联网时间流并不只是newsfeed这一种类型,它还包括消息流、任务流等更细分的内容。Facebook
Home也把消息流很好的给用户展现出来了,但做的并不完美,而且Facebook
Home毕竟只是Facebook
一家的产品,未来用户桌面的互联网时间流会集成Facebook、Twitter、纽约时报、邮件等各种各样的内容。具体有哪些,完全依靠用户添加。

HTC Sence UI的BlinkFeed 功能

二月中下旬,当看到HTC Sence 5.0上的BlinkFeed
功能之后,我的心情相当激动,这就是互联网时间流的真正展现形式。BlinkFeed将你的社交网络、新闻资讯、生活娱乐、照片视频等各种信息一网打尽,直接在你的主屏幕上显示出来。BlinkFeed的信息源来自全球1400多家媒体和网站,同时还可以显示日历等用户信息,基本满足了所以用户的要求。

可能很多人并不习惯这样的浏览方式,而且直接把互联网信息推送到桌面上,对网速、手机续航、内存等也是一个压力。而且如果订阅的信息流很多的话,便会出现信息爆炸的情况,导致用户根本看不过来。不过这些问题都有各种办法来解决或优化,最后一章我们会详细介绍。

HTC的 Sence
UI本身就不错(现在手机也越来越漂亮了),而在手机的交互设计上,这家公司也越来越大胆。BlinkFeed
这种形式虽然现在还有点超前,但随着系统的不断迭代,以后会越来越符合人们的使用习惯。

lifestreams.com

lifestreams.com是一个互联网时间流概念的一个简单Demo,它本身也是根据David
Gelernter的理论设计的。其采用了Google Glass 的 Timeline
Card形式,并根据时间流排序。我们在前一章也介绍过,Timeline Card
这种形式非常适合智能手表、眼镜或其他的小屏幕设备,但在手机或平板上这种展示方式并不合适。

lifestreams.com 虽然严格依据David
Gelernter的时间流互联网概念,但还是太偏理论。不过这种形式基本上给出了未来网络信息展示形态的基本样式,以后的网络信息流会以此为基本形式进行各种更高级的演化。

第三方应用SO.HO

SO.HO是一款Android
App,准确地说,是一款Android启动器(Launcher)。在Google
Play上线也只有一个月左右的时间,和Facebook
Home差不多,SO.HO也是让你在屏幕上直接显示Facebook上的内容,同时还支持Twitter。产品做得很糙,但已经有点未来的意思了。

SO.HO上线两天,Google
Play下就有人评论说:“可以加上Google+、多账户twitter、Foursquare、Instagram、tumblr、RSS”。显然,大家想得都一样,我们可以把手机桌面上塞满各种我们想要的信息……

正如前面在BlinkFeed
那段我们提到的一样,把所有信息都放在一个屏幕上显然很不靠谱。我们应该对其进行合理的分类,比如社交信息、新闻资讯一个屏幕,短信、消息、邮件等一个屏幕,专业内容(工作需要)的东西再放一个屏幕(如BlackBerry
10的Balance生活工作切换功能),这样就简单多了。

 

示例

在这个例子中,我们用一个音乐专辑应用作为示范。不过我并不打算在这里从头到尾展示整个应用,而是把涉及IndexedDB的部分挑出来解释。如果大家对这个Web应用感兴趣的话,文章的后面也提供了源代码的下载。首先,让我们来打开数据库并创建store:

JavaScript

// check if the indexedDB is supported if (!window.indexedDB) { throw
‘IndexedDB is not supported!’; // of course replace that with some
user-friendly notification } // variable which will hold the database
connection var db; // open the database // first argument is database’s
name, second is it’s version (I will talk about versions in a while) var
request = indexedDB.open(‘album’, 1); request.onerror = function (e) {
console.log(e); }; // this will fire when the version of the database
changes request.onupgradeneeded = function (e) { // e.target.result
holds the connection to database db = e.target.result; // create a store
to hold the data // first argument is the store’s name, second is for
options // here we specify the field that will serve as the key and also
enable the automatic generation of keys with autoIncrement var
objectStore = db.createObjectStore(‘cds’, { keyPath: ‘id’,
autoIncrement: true }); // create an index to search cds by title //
first argument is the index’s name, second is the field in the value //
in the last argument we specify other options, here we only state that
the index is unique, because there can be only one album with specific
title objectStore.createIndex(‘title’, ‘title’, { unique: true }); //
create an index to search cds by band // this one is not unique, since
one band can have several albums objectStore.createIndex(‘band’, ‘band’,
{ unique: false }); };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// check if the indexedDB is supported
if (!window.indexedDB) {
    throw ‘IndexedDB is not supported!’; // of course replace that with some user-friendly notification
}
 
// variable which will hold the database connection
var db;
 
// open the database
// first argument is database’s name, second is it’s version (I will talk about versions in a while)
var request = indexedDB.open(‘album’, 1);
 
request.onerror = function (e) {
    console.log(e);
};
 
// this will fire when the version of the database changes
request.onupgradeneeded = function (e) {
    // e.target.result holds the connection to database
    db = e.target.result;
 
    // create a store to hold the data
    // first argument is the store’s name, second is for options
    // here we specify the field that will serve as the key and also enable the automatic generation of keys with autoIncrement
    var objectStore = db.createObjectStore(‘cds’, { keyPath: ‘id’, autoIncrement: true });
 
    // create an index to search cds by title
    // first argument is the index’s name, second is the field in the value
    // in the last argument we specify other options, here we only state that the index is unique, because there can be only one album with specific title
    objectStore.createIndex(‘title’, ‘title’, { unique: true });
 
    // create an index to search cds by band
    // this one is not unique, since one band can have several albums
    objectStore.createIndex(‘band’, ‘band’, { unique: false });
};

相信上面的代码还是相当通俗易懂的。估计你也注意到上述代码中打开数据库时会传入一个版本号,还用到了onupgradeneeded事件。当你以较新的版本打开数据库时就会触发这个事件。如果相应版本的数据库尚不存在,则会触发事件,随后我们就会创建所需的store。接下来我们还创建了两个索引,一个用于标题搜索,一个用于乐队搜索。现在让我们再来看看如何增加和删除专辑:

JavaScript

// adding $(‘#add-album’).on(‘click’, function () { // create the
transaction // first argument is a list of stores that will be used,
second specifies the flag // since we want to add something we need
write access, so we use readwrite flag var transaction =
db.transaction([ ‘cds’ ], ‘readwrite’); transaction.onerror = function
(e) { console.log(e); }; var value = { … }; // read from DOM // add
the album to the store var request =
transaction.objectStore(‘cds’).add(value); request.onsuccess = function
(e) { // add the album to the UI, e.target.result is a key of the item
that was added }; }); // removing $(‘.remove-album’).on(‘click’,
function () { var transaction = db.transaction([ ‘cds’ ],
‘readwrite’); var request = transaction.objectStore(‘cds’).delete(/*
some id got from DOM, converted to integer */); request.onsuccess =
function () { // remove the album from UI } });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// adding
$(‘#add-album’).on(‘click’, function () {
    // create the transaction
    // first argument is a list of stores that will be used, second specifies the flag
    // since we want to add something we need write access, so we use readwrite flag
    var transaction = db.transaction([ ‘cds’ ], ‘readwrite’);
    transaction.onerror = function (e) {
        console.log(e);
    };
    var value = { … }; // read from DOM
    // add the album to the store
    var request = transaction.objectStore(‘cds’).add(value);
    request.onsuccess = function (e) {
        // add the album to the UI, e.target.result is a key of the item that was added
    };
});
 
// removing
$(‘.remove-album’).on(‘click’, function () {
    var transaction = db.transaction([ ‘cds’ ], ‘readwrite’);
    var request = transaction.objectStore(‘cds’).delete(/* some id got from DOM, converted to integer */);
    request.onsuccess = function () {
        // remove the album from UI
    }
});

是不是看起来直接明了?这里对数据库所有的操作都基于事务的,只有这样才能保证数据的一致性。现在最后要做的就是展示音乐专辑:

JavaScript

request.onsuccess = function (e) { if (!db) db = e.target.result; var
transaction = db.transaction([ ‘cds’ ]); // no flag since we are only
reading var store = transaction.objectStore(‘cds’); // open a cursor,
which will get all the items from database store.openCursor().onsuccess
= function (e) { var cursor = e.target.result; if (cursor) { var value =
cursor.value; $(‘#albums-list tbody’).append(‘ ‘+ value.title +”+
value.band +”+ value.genre +”+ value.year +’

1
2
3
4
5
6
7
8
9
10
11
12
request.onsuccess = function (e) {
    if (!db) db = e.target.result;
 
    var transaction = db.transaction([ ‘cds’ ]); // no flag since we are only reading
    var store = transaction.objectStore(‘cds’);
    // open a cursor, which will get all the items from database
    store.openCursor().onsuccess = function (e) {
        var cursor = e.target.result;
        if (cursor) {
            var value = cursor.value;
            $(‘#albums-list tbody’).append(‘
‘+ value.title +”+ value.band +”+ value.genre +”+ value.year +’

‘); // move to the next item in the cursor cursor.continue(); } }; }

这也不是十分复杂。可以看见,通过使用IndexedDB,可以很轻松的保存复杂对象,也可以通过索引来检索想要的内容:

JavaScript

function getAlbumByBand(band) { var transaction = db.transaction([
‘cds’ ]); var store = transaction.objectStore(‘cds’); var index =
store.index(‘band’); // open a cursor to get only albums with specified
band // notice the argument passed to openCursor()
index.openCursor(IDBKeyRange.only(band)).onsuccess = function (e) { var
cursor = e.target.result; if (cursor) { // render the album // move to
the next item in the cursor cursor.continue(); } }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function getAlbumByBand(band) {
    var transaction = db.transaction([ ‘cds’ ]);
    var store = transaction.objectStore(‘cds’);
    var index = store.index(‘band’);
    // open a cursor to get only albums with specified band
    // notice the argument passed to openCursor()
    index.openCursor(IDBKeyRange.only(band)).onsuccess = function (e) {
        var cursor = e.target.result;
        if (cursor) {
            // render the album
            // move to the next item in the cursor
            cursor.continue();
        }
    });
}

使用索引的时候和使用store一样,也能通过游标(cursor)来遍历。由于同一个索引值名下可能有好几条数据(如果索引不是unique的话),所以这里我们需要用到IDBKeyRange。它能根据指定的函数对结果集进行过滤。这里,我们只想根据指定的乐队进行检索,所以我们用到了only()函数。也能使用其它类似于lowerBound()upperBound()bound()等函数,它们的功能也是不言自明的。

手机、Google Glass、智能手表、平板、电视……

移动互联网的发展,不仅让网络时间流特性更加明显、信息更加扁平化,同时对于普通大众来说,最大的变化便是多屏化趋势、以及每个屏幕信息扁平化展现形式的变化。而这最重要的一个原因,就是互联网从PC
走向手机、电视、手表等物联网时代的各种设备。本章我们就介绍一下各种大大小小的屏幕之间的差别、互联网内容在这些设备上的展现方式。

图片 5

在互联网还仅局限于PC
上之前,业内就有第一屏幕(电视)、第二屏幕(手机)、第三屏幕(PC)等等的说法。后来随着科技的发展,手机渐渐成为了第一屏幕,平板兴起并开始和电视争夺客厅的掌控权,而手表、眼镜也成了新兴屏幕,更别提Nest、冰箱、微波炉这些小屏幕了。

智能手机

移动互联网的发展,已经让智能手机成为了PC之外兼容互联网内容最优的设备,未来的网络内容展现形式和现在差异也不会太大。但手机的演化,也会使得未来我们使用手机的方式有些不同。

首先,手机屏幕越来越大,从3.5英寸到4英寸,从4英寸到5甚至5.5英寸,人们开始慢慢接受大屏幕。屏幕一大,自然呈现的信息就多,很多隐藏的很深的信息便可以直接放到桌面上,比如天气、信息、各种小插件等。这符合互联网时间流的变化,信息层级变浅,更多内容聚集到桌面上。

其次,触屏手机的流行,使得未来语音、智能传感器(如眼动仪、距离感应器等)得到发展。未来只需对着手机说句话,它就会告诉你任何信息,你不用去打开某款App,设备就可以自动从网络上找到你想要的东西。信息进一步扁平,HTML5网站内容可直接呈现在手机屏幕上。

平板电脑

平板电脑的流行也就这两三年的事(2010年iPad第一代发布),虽然之前也有各种Pad
概念和设备。平板延续了智能手机的操作系统,导致其易用性也比PC更高。相比PC
这种生产力工具,平板更像是一个生活设备,而大部分家庭需要的,也只是用来休闲娱乐的生活设备。

所以整体上,平板和智能手机差不多,在互联网内容兼容、内容展示方式、人机交互等方面都已经非常成熟了。随着互联网时间流的扁平化,未来的平板更像是一个信息流自动展示平台。

智能电视

电视以前是客厅的霸主,现在平板的出现让人们在客厅也有了其他的事情可做,但智能电视很有可能挽回这种局面。和平板一样,智能电视也是一个互联网的时间流展示平台:所有内容在人们不看电视的时候自动滚动一些信息,比如天气、新闻、社交好友照片、新信息、分享内容等。而且智能电视的视讯系统和手势操控,能分别控制客厅视频通话和游戏这两大项目,在电视前和家人视频聊天、玩游戏是再自然不过的事了。

在网络信息流展示形式上,电视相比平板其呈现内容更少(虽然屏幕大但距离远),所以电视上的内容更偏向于后面的要讲的眼镜,即卡片式展示。除了语音和手势控制,电视上都是以大块内容展示的,比如一个电影海报可能就占据了半个屏幕,一场球赛直播可能就占据了3/4甚至更多的屏幕。但从目前智能电视的界面设计看,还没有做的很好的展现方式。

智能眼镜(Google Glass)

虽然本段我们以Google
Glass为例,但这里要声明的是:智能眼镜并不单独指Google
Glass这种形式。Google
Glass在智能眼镜研发上做的很好,但不排除未来会有其他的形式(比如Vuzix
的Smart Glasses M100),而且微软、索尼、Bluester
等竞争对手的加入,可能也会让智能眼镜领域拥有更多样性的生态。

在互联网时间流概念上,Google Glass
的信息展现方式可以说是最典型的了:Timeline Card 。Glass
的每一个信息都是一个小卡片,并以时间为排序方式。卡片上可以显示天气、时间、照片、短消息、视频通话等等,Google
把互联网内容进行了分解,社交好友的一条状态、Instagram上的一张图片都只放在一张卡片上,这样信息更加集中,也不会给用户造成干扰。

Google
Glass的这种“时间流卡片”的展示方式可以用在很多设备上,比如智能电视、智能手表、冰箱、洗衣机、Nest智能家居检测仪等。由于可是屏幕足够小,所以这种方式比较适合。而且HTML5的跨平台特性,也能让网络资源在这些小屏幕设备上很好展现。

智能手表

智能手表有很多,它可能也会像智能眼镜一样成为各大科技厂商的战略性产品,而且由于智能手表门槛要比眼镜低,可能更会有一批小厂商也涌进来。如果我们拿Pebble 为例,就可以知道手表屏幕很小,只能显示很少的内容,所以Timeline
Card的形式也适用,在此我们就不多说了。

但智能手表和智能眼镜都面临着同样的一个问题:由于体积太小,导致硬件受限,很难开发一个独立的操作系统,只能通过连接到手机成为一个显示屏。(虽然Google
Glass是独立运行的,但未来不保证其他眼镜也能解决这一问题。)

PC

互联网就是在这上面诞生的,PC
的价值毋庸置疑。但科技的发展,已经让PC慢慢退居二线了,我们现在绝大部分操作都可以在移动终端上完成,未来也不保证不会完全抛弃PC
。有人说,现在的PC 不应该叫PC 了,应该叫WC (Work Computer)。确实,PC
现在基本上成为了一个生产力工具,人们下班之后基本都不会摸电脑了,更何况对于老人孩子还非常难用。

 

AppCache

如果你的Web应用中有一部分功能(或者整个应用)需要在脱离服务器的情况下使用,那么就可以通过AppCache来让你的用户在离线状态下也能使用。你所需要做的就是创建一个配置文件,在其中指定哪些资源需要被缓存,哪些不需要。此外,还能在其中指定某些联机资源在脱机条件下的替代资源。

AppCache的配置文件通常是一个以.appcache结尾的文本文件(推荐写法)。文件以CACHE MANIFEST开头,包含下列三部分内容:

  • CACHE – 指定了哪些资源在用户第一次访问站点的时候需要被下载并缓存
  • NETWORK
    指定了哪些资源需要在联机条件下才能访问,这些资源从不被缓存
  • FALLBACK – 指定了上述资源在脱机条件下的替代资源

发表评论

电子邮件地址不会被公开。 必填项已用*标注