单页 Web 应用概述

单页 Web 应用概述

传统的 Web 应用通过加载整个 Web 页面来实现与用户的交互。当用户点击一个链接或提交一个表单时,浏览器将向服务器请求一个全新的页面。这涉及到获取新页面的数据、卸载旧的页面和绘制新的 页面。按照这种方式进行用户交互势必影响到 Web 应用的性能。并且,由于网络延时的存在,页面与页面之间的切换很可能会不流畅,从而进一步影响用户体验。

SPA 能够缓解传统的 Web 应用存在的问题。有关 SPA 的详细介绍可以访问 参考资源 以获得更多的信息。SPA 规定在一个页面的生命周期中不会有页面的重新加载,所有的用户交互和页面内容变换将限制在同一个 Web 页面中。换言之,SPA 用 Web 页面的局部变更来代替整个页面的重新加载,从而提高了用户体验和整体性能。

目前 SPA 已经有了较为广泛的应用,如 Google Docs、Gmail 等都是单页 Web 应用。

但是,相比于传统的 Web 应用,SPA 也存在着以下问题。

  • SPA 中动态变化的内容可能不会被搜索引擎找到。如果你的 Web 页面的内容希望被搜索引擎找到,那就不应该选择 SPA。
  • 需要特殊处理才能实现浏览器的“后退”和“前进”功能。如何利用 Dojo 实现该功能可以参考:使用 Dojo 为 Ajax 应用增添前进 / 后退能力的两种解决方案
  • SPA 需要在一个 Web 页面周期中加载所有需要的 HTML、CSS 等资源。这样有可能造成初次加载时间较长。本文将在“在创建适用于单页 Web 应用的 UI 布局”中介绍缓解该问题的方法。

Dojo 框架:Dojo 是一个强大的前端框架,它提供了方便的 Ajax 方法、丰富的小部件、数据结构、辅助函数、效果和布局帮助。有关 Dojo 的详细介绍请参考 Dojo 技术专题。Dojo 是一个较为活跃的开源项目,截止到 2012 年 8 月,Dojo 的最新版本是 1.8.0。本文中的所有实现将基于 Dojo 1.6.0。

综上所述,本文将分别从 Application controller 和 UI layout 的角度,详细介绍一种利用 Dojo 实现 SPA 的方法。

加载 Dojo,搭建开发环境

加载 Dojo

选择从 Google CDN 上加载完整的 Dojo Toolkit。由于部分文件在本地,所以需要借助 dojoConfig 中的 baseUrlmodulePaths来注册本地文件。在代码清单 1 中注册了一个本地模块“app”,这样在 Web 页面的地址下的 app 路径中的所有文件都可以被 Dojo 文件系统找到。


清单 1. 加载 Dojo Toolkit

<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.6.0/dojo/dojo.xd.js"
   data-dojo-config="parseOnLoad: true, baseUrl: './', modulePaths: { app: 'app' }"
></script>

 

准备开发环境和调试工具

下载并安装 Firefox 浏览器,并安装 Firebug 插件。

创建一个 Application controller

Application controller 的作用

作为一个模块化的控件库,大部分的 Dojo 的模块都是相对独立存在的。基于 Dojo 构造一个 Web 应用时,需要一个框架将这些模块(数据、UI 布局等)组装起来。Application controller 所起的作用主要是连接各个模块。同时,对于 SPA,在其生命周期内只会进行页面的局部更新,Application controller 还要肩负着记录各个模块状态和各个模块数据交互的任务。在实际应用中,Application controller 就是一个 JavaScript 对象,所有与 SPA 相关的内容,如数据、UI 布局、行为控制等都存放在这个对象中。有关 Application controller 的详细介绍请访问 参考资源

创建 Application controller 的一种方式

由于 Application controller 是一个 JavaScript 对象,因此创建的方式有多种。清单 2 利用 Dojo 的 module 机制创建一个对象作为 Application controller,这样能更好的将 JavaScript 和 HTML 分离。本文将在函数 startup 中完成对 SPA 的 UI 布局的初始化,下一节将详细介绍,这里先打印信息到 Firebug 的 Console 面板上。


清单 2. 创建一个空的 Application controller

				
// 向 Dojo 的文件系统注册一个模块“app.Application”
 dojo.provide("app.Application"); 

 dojo.declare("app.Application", [], { 
    startup: function() { 
        console.log("SPA starts up."); 
    } 
 }); 

 

由于在“加载 Dojo,搭建开发环境”中已经将 app 注册在 Dojo 的文件系统中。因此只要再调用 dojo.require 即可进行 Application controller 的实例化。清单 3 演示了如何利用 Application controller 初始化 SPA。


清单 3. 用 Application controller 初始化整个页面

				
 <script> 
 // 从 Dojo 的文件系统获取模块“app.Application”
    dojo.require("app.Application"); 

    dojo.ready(function() { 
        (new app.Application()).startup(); 
    }); 
 </script> 

 

开发人员可以向 Application controller 添加方法来实现单页应用所需要的功能。如,可以添加 refresh 方法实现内容的更新。您可以在随本文提供的示例代码中看到 refresh 方法的声明及使用。

创建适用于单页 Web 应用的 UI 布局

UI 布局对于任何一个 Web 应用都很重要。传统的 web 开发利用 HTML 元素和 CSS 样式实现 UI 布局,在一些复杂的应用场合,这将会耗费大量的开发时间。Dojo 为开发人员提供了大量的布局控件,基于这些控件能够简单的实现复杂的 UI 布局。Dojo 提供的布局控件在 dijit.layout 中。这一小节将介绍用这些布局控件来构造一个具有二级菜单的单页 Web 应用。同时介绍如何实现延迟加载和分步加载来减少 SPA 的初始加载时间。

UI 布局控件概述

Dojo 提供了多种布局控件,本文将只对用到的布局控件进行概述。

  • dijit.layout.BorderContainer: 这是一个容器,它将 Web 页面划分为五个区域,分别为 “top”、“bottom”、“left(leading)”、“right(trailing)”和“center”。
  • dijit.layout.TabContainer: 这是一个容器,它包含了多个面板,一次只显示其中的一个面板。
  • dijit.layout.ContentPane: 这是 dijit.layout 中最基本的布局面板,可以在其内部嵌入页面元素及子控件。

构建单页 Web 应用

本节将以一种从外向内的方式,逐步介绍如何利用上述的布局控件,实现一个具有二级菜单的 SPA。

首先,创建 BorderContainer 来管理最外层的 UI 布局。清单 4 演示了这一步骤。在清单 4 中,我们只用了 BorderContainer 的“top”和“center”区域。


清单 4. 创建 BorderContainer 容器

				
 // 创建最外层的 BorderContainer 
 var borderContainer = this.borderContainer = new dijit.layout.BorderContainer({ 
    design:"headline", 
    style: "width: 1000px; height: 600px;", 
 }, "borderContainer"); 
 // 创建页面的 header 
 var headerContent = this.headerContent = new dijit.layout.ContentPane({ 
    style : "height:100px", 
    region: "top", 
    href: "header.html", 
    onLoad: function(){ 
        console.log("Loading Header"); 
    } 
 },dojo.create("div")); 
 borderContainer.addChild(headerContent); 
 // 创建用于管理主区域的 TabContainer 
 var centerTabContainer = new dijit.layout.TabContainer({ 
    region: "center", 
    tabPosition: "top", 
 }, dojo.create("div")); 
 borderContainer.addChild(centerTabContainer); 
 // 启动控件
 borderContainer.startup(); 

 

之后,我们在管理主区域的 TabContainer 中添加一级菜单的子页面,清单 5 演示了这一步骤。


清单 5. 创建一级菜单的子页面

				
 // 创建一级菜单中的子页面
 var aboudTab = this.aboudTab = new dijit.layout.ContentPane({ 
    title: "About" , 
    href: "about.html", 
    onLoad: function(){ 
        console.log("Loading " + this.title); 
    } 
 },dojo.create("div")); 
 centerTabContainer.addChild(aboudTab); 

 

这里创建的一级菜单子页面将从“about.html”加载所需的内容,并在加载时向 Firebug 的 Console 面板打印相应的信息。

在实际应用中,如果 Web 应用需要显示的信息较多,可以采用一种二级菜单的方式进行管理,即在相应的一级菜单子页面下,再创建第二级菜单。通过选择第二级菜单,最后定位到相应的内容。清单 6 演示了如何创建第二级菜单。


清单 6. 创建二级菜单及其子页面

				
 // 创建用于管理二级菜单的 TabContainer 
 var musicTabContainer = this.musicTabContainer = new dijit.layout.TabContainer({ 
    region: "center", 
    nested: true, 
    tabPosition: 'left', 
    title: 'Music', 
 }); 
 centerTabContainer.addChild(musicTabContainer); 
 // 创建二级菜单中的子页面
 var folkMusicTab = this.folkMusicTab = new dijit.layout.ContentPane({ 
    title: "Folk" , 
    href: "folk.html", 
    onLoad: function(){ 
        console.log("Loading " + this.title); 
    } 
 },dojo.create("div")); 
 musicTabContainer.addChild(folkMusicTab); 
 var artMusicTab = this.artMusicTab = new dijit.layout.ContentPane({ 
    title: "Art" , 
    href: "art.html", 
    onLoad: function(){ 
        console.log("Loading " + this.title); 
    } 
 }); 
 musicTabContainer.addChild(artMusicTab); 

 

从清单 6 可以看出,创建二级菜单实际上就是在一个 TabContainer 中管理另一个 TabContainer。用类似的方法可以创建三级、四级或者更多级的菜单。这里创建的二级菜单子页面将从相应的资源文件加载所需的内容,并在加载时向 Firebug 的 Console 面板打印相应的信息。

最后,利用上述方法实现的 UI 布局如图 1 所示。


图 1. UI 布局实现效果

分析

利用上述的方法构建的二级菜单 Web 应用,可以实现在一个 Web 页面的生命周期内,动态的切换多个子页面。同时,上述实现方法还具有以下优点:

  • 延迟加载。即在初次加载应用时,只加载需要的部分。其他的部分只在用户需要的时候才去加载。这样可以减少初始加载的时间,提高用户访问速度。在上述的实现 过程中,所有的子页面都会在“OnLoad”事件触发时向 Firebug 的 Console 面板打印信息。运行本文提供的示例代码可以发现,在初次加载时,仅仅 Header 和一个子页面被加载了。
  • 局部更新。即切换子页面时,仅仅是子页面内的内容变换了,其他区域(例如 Header)并没有重新加载。这样提高了 Web 应用的响应速度。

综上所述,本节描述的 UI 布局实现是一种符合 SPA 特性的实现方法。

总结

通过以上的介绍和举例,我们了解了一种以 Dojo 作为工具 , 创建单页 Web 应用的方式。在 Firefox 中运行本文提供的示例代码,可以看到一个介绍音乐分类的简单 Web 应用。该 Web 应用在不重新加载 Web 页面的前提下,能够对其内容进行定时刷新。

单页 Web 应用只是一个概念,对于其实现没有一个固定的模式,甚至基于 Dojo 也可以有多种实现方式。本文只是从一个角度介绍了一种实现方式,希望能为您的实际应用带来一定的启发。

 

下载

描述名字大小下载方法
示例代码 SinglePageApplication.zip 4KB HTTP

关于下载方法的信息

 

参考资料

学习

讨论

加入 developerWorks 中文社区。查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。

posted @ 2013-03-01 14:35  Mose  阅读(835)  评论(0编辑  收藏  举报