[置顶] 筋斗云框架前端:“变脸式应用”的页面路由设计

注意:文中多次出现网页(Web page)与页面(或逻辑页面,Page),请注意区分。

制作多页面的移动Web应用,主要有以下两种方式:

移动站点式。每个页面是个独立网页,页面切换时整体刷新。这种做法优点是单个页面加载快,缺点是页面切换时体验差,尤其是网速不太好时,网页加载痕迹明显,出现白屏,然后界面轮廓逐渐显示出来,时而还会出现闪烁或抖动。同时,由于每次后台请求都是整个网页,与原生App只请求业务数据相比,不仅远费流量,而且没有彻底分离数据模型与视图展示(Model/View分离),架构不清晰。尽管如此,这仍是目前主流做法,比如大众点评网的移动站点。由于体验不佳,像淘宝等应用已经放弃移动站点的开发,只推原生App(淘宝的App也是混合应用,使用自己的框架,做了很多优化)。

逻辑页面式。所谓逻辑页面,就是每个应用页面其实是一个DOM元素,不是真正的完整网页。页面切换时,网页不会刷新,只是将另一个逻辑页面放到最前端显示而已,由于无网页刷新,各页面间可共享全局变量或相互操控。这种做法可以解决移动站点中的网页切换体验差的问题,而且这类应用一般都做成是“单网页应用”(SPA),区分前端与后端,两者之间只传输业务数据,不仅省流量,架构也相对清晰,其后端应用服务器可以被Web应用和原生应用所共享。

使用逻辑页面的Web应用程序,又称为“变脸式应用”

川剧中的变脸,以精湛的特技展现出快如闪电、随心所欲的艺术效果。如果把一个应用程序有九个页面比喻成有九张脸,那么原生应用就像神话中的九头鸟,天生就有九张脸,切换起来很自然;而移动站点则是有九个人九张脸,切换起来这些人跑来跑去,显的太重;“变脸式应用”则只需要一个人,通过换不同的面具或局部更新,达到九张脸自由切换的效果,其体验与原生应用类似。

看起来变脸式应用与移动站点式相比,用户体验更好,架构更清晰,也省流量。那为什么用的人不多呢?正如会表演变脸的艺术家不多一样,要做好表演需要精湛的技术。变脸式应用如果手法不精湛,就会出各种问题。

川剧变脸的主要手法主要有抹脸、吹脸、扯脸等,而变脸式应用的手法,一般称为页面路由。常见的做法,是通过URL中的hash(即井号后的部分)来确定页面,其原理是,当访问订单列表页面http://server/app/index.html#orders时,框架从当前网页里找到并打开id=orders的逻辑页面来显示。这需要把所有逻辑页面都放在一个主网页中,用到哪个页就只显示哪个,主网页结构像这样:

<html>
    <head>...</head>
    <body>
        <div id="pages" style="display:none">
            <div id="home"></div> <!-- 逻辑页面:主页 -->
            <div id="orders"></div> <!-- 逻辑页面:订单列表 -->
            <div id="ad"></div> <!-- 逻辑页面:广告页 -->
        </div>
    </body>
</html>

这对于页面不太多的应用还可以,但如果页面过多,用户初次加载就会很慢,而且运行时也会占用过多内存,造成卡顿。对于开发来说,所有的逻辑页面都集中写在一个网页里,开发与维护都很不方便。就像变脸时,需要太多面具,操作起来难免会手忙脚乱。

为了改进这个问题,一些框架采用了“主网页+子网页”模式,允许你把常用的逻辑页面都放在主网页中,而其它页面以HTML片段的方式保存在单独文件中(称为子网页),需要时通过ajax动态加载进来。JQM(jQuery Mobile)框架支持这种做法,当你从页面http://server/app/index.html#orders跳转到另一个地址http://server/app/subpage/ad.html(假如是一个广告页)时,并不发生网页刷新,而是框架动态加载了subpage/ad.html页面,实现“换脸”。而且这个页面也不是完整网页,只是一个网页片段,比如只是一个DIV:

<!-- 子网页ad.html,只含一个逻辑页面,是个HTML片段 -->
<div id="ad"></div> <!-- 广告页 -->

然而,这种方案又带来一个“入口页面限制”问题:用户无法直接打开不在主网页之内的逻辑页面,因为逻辑页面根本就不是完整网页;也就是说,外置页面不能做为入口页面。在上面的例子中,外置的广告页是没法直接打开的,只能通过主网页中的页面链接过去。这好比表演变脸时,只能从指定的几张面孔开始变,不能随心所欲的选择第一张面孔。

JQM框架对这个问题的解决方案是:放弃“主网页+子网页”模式,所有可能做为“入口”的页面都必须是一个完整的网页(即都是“主网页”),框架在动态加载这些网页时,会忽略头尾部分,只取其中第一个逻辑页面来显示;同时,所有的入口网页,都必须具有相同的头尾结构和内容,以保证不管从哪个逻辑页进入时,显示结果和应用逻辑是一样的。这个方案是很不完美的,首先,维护多个头尾部相同的网页,忍受重复是一件让开发者非常难受的事情,其次,这些重复部分在运行时多费了很多流量。再者,这种方案要求所有的网页都只能包含一个逻辑页,因为从别的页面跳过来时,只能访问到第一个逻辑页。这使得发布时,没法通过合并常用网页到主网页来做优化。

筋斗云移动端支持“主网页+子网页”模式,它采用“缺页中断”技术来处理“入口页面限制”问题。这是一种特别的页面路由设计。继续上面的例子,广告页是一个子网页,URL是subpage/ad.html,但在访问该页面时,并不使用这个地址,而是仍然使用hash来访问,如#ad。框架在当前网页中找id=ad的页面,发现该页不存在,于是产生类似虚拟内存管理中常见的“缺页中断”,继而去地址subpage/ad.html来找这个逻辑页并加载进来。

筋斗云统一使用URL hash来找逻辑页。在开发时,主网页一般不包含任何逻辑页,访问任何一个页面时都会发生缺页,开发者不用关心细节,框架会自动加载相关页并显示出来。在发布时,可以将常用的逻辑页合并到主网页中,从而优化应用。

当然,这种设计也有一些局限性:所有逻辑页不能重名,否则可能产生错乱;由于页面间链接可能是虚拟的,对搜索引擎不够友好。对制作一个以逻辑为主的应用程序(而非网站)来说,这些缺点都还是可以接受的。

你可能感兴趣的:(框架,前端,移动,Web应用,筋斗云)