不需要 Npm 的单页应用框架:
正如前文所述,每个视图都是唯一的,都有唯一的ID与之对应。视图ID,作为视图的唯一性标记,是浏览位置、代码区域,以及视图导向的主要参考系。
视图切换时,视图ID清晰地表述了切换操作的目标位置,使得View.js可以没有歧义地完成视图导航。
但这不是问题的全部。有一些场景,是视图ID所无法“完美”应对的。例如:
为了最大限度的节约研发成本,提升软件利润,软件公司会将一套程序销售给多家需求相近的客户。
这些客户大多对软件的整体UI和功能基本满意,但细微之处又各有各的诉求。可能是界面布局,也可能是业务逻辑,抑或是功能的丰富完善或调整。
相比整个软件功能,这些差异化的诉求所占据的工作量,可能不足10%,也可能高达40%,甚至于70%。
软件公司不可能因为这些客户不是“没有一点意见的完美客户”就放弃订单,但把代码在工程中分别硬拷贝生成多份的操作,又会把摊子铺的太大,担心维护成本会一下子放大很多。
软件公司的担心不无道理。没有人会乐意将同一个故障的修复过程一遍遍的向多个工程中同步。
针对这个问题,View.js建议软件公司将实现的视图功能放到一个巨大的视图仓库中,借助构建脚本将视图“安装”到客户的页面上去。对于客户提出的个性化诉求,软件公司可以将其以视图为单位进行实现。
这样一来,对于一个电商首页,可能就会出现多个副本(首页作为门户入口,是客户的重点关注对象,改造需求自然要多一些),如下所示:
借助这种方式,差异化诉求的实现成本,就降低到了可量化计算的多个视图的功能开发上,而对于没有个性化诉求的共用视图,则始终只有一份副本。如此一来,可以“头疼医头,脚疼医脚”,能够极大地节约软件公司的开发资源。与此同时,开发团队也能够持续不断地积累仓库,使得复用能力越来越强。
但是,这和视图群组有什么关系呢?
实施上述做法的挑战之一,是如何在 profile 视图中动态地决定要跳转到 home-page1 还是 home-page2。拙劣的做法,就是判断哪个视图存在,然后决定跳到哪里去。代码片段如下所示:
var homePageViewIds = [
"home-page1",
"home-page2"
];
for(var i = 0; i < homePageViewIds.length; i++)
if(View.ifExists(homePageViewIds[i])){/* 查找存在的视图 */
View.navTo("homePageViewIds[i]");
break;
}
这样做不是不行,但profile和首页之间的关系,已经开始变得紧密起来,而且随着首页替代品的丰富,profile的代码也不得不不断调整,无法做到一劳永逸。工程化的实施诸多要求之一,便是尽量减少模块之间的耦合关系。
那么视图群组是如何优雅地解决这个问题的呢?
视图群组,用于将多个功能或地位类似的视图在命名空间上统一起来,以实现别名化的代替。
视图群组使用dom属性:“data-view-group” 在视图的骨架元素上定义,如下所示:
<!DOCTYPE HTML>
<html>
<head>
<link rel = "stylesheet" href = "main.css"/>
</head>
<body>
<section id = "home-page1" data-view-group = "home-page" data-view = "true" >
...
</section>
</body>
</html>
视图群组完成定义后,就可以使用群组名称完成视图切换操作,如下所示:
View.changeTo("~home-page");// 等同于 View.navTo("home-page1")
其中"~"符号用于标识视图群组名称,以与具体的视图ID或伪视图区分开来。
因此,对于上面描述的问题,只要 home-page1 和 home-page2 均声明了视图群组为 home-page,并且profile是以视图群组的方式完成的视图切换,那么profile就可以一劳永逸地正确完成向 首页 视图的跳转。
使用视图群组执行视图切换时,View.js将根据提供的群组名称查找页面内属于该群组的所有视图。如果没有视图隶属于该群组,则在控制台上提示相关错误;如果有多个视图隶属于该群组,则认定通过 View.listAll(groupName)
方法得到的第一个视图为要导向到的目标视图,并将视图切换过去。