移动 Web 应用程序框架比拼,第 4 部分: 依赖于 Sencha Touch 的一个完整移动 Web 解决方案


关于本系列
移动开发已经启动,许多开发人员都选择使用移动 Web,而不是为每个不同的移动平台反复编写同一个应用程序。然而,“实现 Web 化” 放弃的东西之一是使原生移动应用程序开发人员的生活变得轻松的应用框架。因此,出现了多个 Web 应用程序框架。此系列文章由四部分组成,我们将讨论其中的四个框架:SproutCore、Cappuccino、jQTouch 和 Sencha Touch。我们将比较这些框架的特性并评估使用这些框架来构建移动 Web 应用程序的利与弊。

先决条件
在本文中,我们将展示 Sencha Touch 移动 Web 应用程序框架。Sencha 是面向对象的 JavaScript 框架,因此拥有使用 JavaScript 的经验(以及 Web 开发的其他核心技术如 HTML 和 CSS)将有助于您的理解。样例应用没有服务器端组件,因此任何静态 Web 服务器便足够了。参见 参考资料 获得到这些工具的链接。

Sencha 的演变
如果您拥有 Web 开发经验,那么您可能听说过甚至曾经使用过 Sencha,或许当时它被称为 Ext JS 甚至 YUI-Ext(Yahoo! UI 框架的扩展)。多年来,它曾被称为 YUI-Ext、Ext JS、Ext 2.0、Ext 3.0,现在称为 Sencha Touch。对移动 Web 应用程序新投入关注部分归因于将 jQTouch “合并” 到 Ext JS 中。然而,您将看到,Sencha 与 jQTouch 差别迥异。
首先,它根本不依赖 jQuery,相反,基于 Ext JS。当然,Ext JS 因为与 jQuery 和 Prototype 等其他 JavaScript 库的兼容性,过去一直深受好评。它的卖点包括其部件库,有更加面向对象的 API 集,更加完整。Sencha Touch 也具有这些特性。然而,部件库是全新的,且专为移动浏览器进行了优化,特别是对于 iOS 和 Android 设备。为了更好地了解如何把 Sencha Touch 用于移动 Web 应用程序,让我们看看样例应用;它是新版本的内联网员工目录应用程序,在本系列以前的各篇文章中都有涉及。参见 下载,了解该应用程序的源码。

Sencha Touch 应用程序开发
在本系列的课程中,我们已经研究了多个客户端侧 Web 应用程序框架。Sencha Touch 与其他框架相比有何独特之处?答案是 Sencha Touch 既是一个完整的框架(囊括了从执行 Ajax 调用的实用工具到丰富的 UI 部件集的所有项目),又为移动 Web 浏览器而构建。(特别是,它专为 iOS 和 Android 设备上基于 WebKit 的浏览器而构建,尽管该系列可能会随着基于 WebKit 的浏览器继续主导移动领域而在未来进行扩展。)这是一种独特的组合,可能非常引人注目。
此外,Sencha Touch 不是一个新的、未经测试的移动 Web 框架。相反,它拥有悠久的历史,多年来深受 Web 开发人员的欢迎。在它背后有活跃的开发人员,周围有大型社区。Sencha Touch 甚至曾经被 Adobe 的 ColdFusion 等大型开发框架进行过重新包装和重用。
正如您所期待的,Sencha Touch 继承了许多使 Ext JS 深受 Web 开发人员欢迎的特性。它不仅提供了用于应用开发的完整的 框架,同时也提供了面向对象的框架。追溯到 Smalltalk-80,用户界面框架已经使用面向对象的模型。虽然面向对象的编程并非适用于每个编程问题,但它非常适用于大多数用户界面挑战。JavaScript 可以认为是面向对象的,尽管不是常见的基于类的方式。由于它使用基于原型的面向对象的编程方式,您不用从类继承;相反,您可以克隆该类的实例并修改其原型,重写现有的行为或将新的行为添加到对象。大多数开发人员不熟悉这种风格的面向对象的编程,而是更喜欢基于类的继承。Ext JS 提供了基于 JavaScript 的实用工具将基于类的面向对象的编程提供给开发人员。此外,它还使用经典的(基于类的)面向对象的组件模式构建扩展的 UI 部件库。同时,Ext JS 使用惯用的 JavaScript。例如,大多数 Ext JS 对象的构造函数把 JavaScript 物件实字当做其惟一的输入参数。可将该对象看作一个配置对象,但是在许多方面,它类似于拥有已命名参数的构造函数。这对于在对象可能有很长串的值必须导入其中进行正常构造时非常有利。
当然,Sencha Touch 不仅仅是 Ext JS,还为移动 Web 进行了优化。这意味着,不仅其小部件的设计带有小屏幕,还专为处理敲和击等触摸事件以及设备方向变更而设计。将这两者结合在一起,便是功能非常强大的功能集。然而,由于对于大多数开发人员来说,眼见为实,因此让我们看看 Sencha Touch 支持的移动 Web 应用程序样例。

数据模型、存储和 Ajax
样例应用程序是对本系列以前所示员工目录应用程序的另一个实现。请记住该应用程序显示员工列表及其联系信息。Sencha Touch 允许您为该应用程序定义一个数据模型。清单 1 显示了该 Employee 数据模型。

清单 1. Employee 数据模型,Sencha Touch 样式

Ext.regModel('Employee', {
    fields: [
        {name:'firstName', type: 'string'}, 
        {name: 'lastName', type: 'string'}, 
        {name:'email', type:'string'},
        {name: 'phone', type: 'string'}
    ]
});

通过 Sencha Touch 可以轻松地定义模型及其字段。只提供一个字段数组,每个字段都定义其名称和类型。结果是该模型可与 UI 组件配套使用,在本文的后续章节会涉及。然而,现在加载一些可以解析到 Employee 对象的一些远程数据。使用 Sencha Touch 的数据存储对象(以及少量 Ajax)来执行该任务。清单 2 显示了如何定义数据存储。

清单 2. 创建 Sencha Touch 数据存储

var store = new Ext.data.JsonStore({
    model  : 'Employee',
    sorters: [
             {property: 'lastName', direction: 'ASC'},
             {property: 'firstName', direction: 'ASC'}
        ],
    getGroupString : function(record) {
        return record.get('lastName')[0];
    },
    proxy : {
        type : 'ajax',
        url : 'app/employees.json',
        reader : {
            type : 'json',
            root : 'employees',
            idProperty : 'email'
        }
    },
    autoLoad : true
});

数据存储是 Sencha Touch 框架的一个重要组成部分。存储提供了用于可以与框架中的各种 UI 组件配套使用的模型对象的客户端侧缓存。它负责检索远程数据,查询数据,整理数据等。在清单 2 的存储情况下,它宣布其模型为 Employee,该模型在清单 1 中进行了注册。它然后宣布该数据上的分类元素,lastName 和 firstName。因此,该数据的自然分类将按 lastName 升序执行,然后按 firstName 升序执行。下一步,该存储宣布 getGroupString 函数。该函数将应用于该存储中的每个记录 (Employee),将它们归组在一起。在这种情况下,您指示它采用 lastName 并使用其首字母,这样,所有姓以 'G,' 开头的员工都被归组。这只用于支持分组的 UI 组件中。由于您将使用的组件的确支持分组,将该函数添加到存储从而利用它。
下一节介绍了其代理。Sencha Touch 有几种不同类型的代理。例如,它提供了一种使用 HTML5 localStorage 对象 Ext.data.LocalStorageProxy 的代理。如果您以前已经使用 localStorage 本地保存了数据,那么您可以使用 LocalStorageProxy 加载这些数据,然后将其与 Sencha Touch UI 组件配套使用。这是 Sencha Touch 如何提供可以在 iOS 和 Android 浏览器上使用的 HTML5 功能的良好示例。
清单 2 中的示例数据没有进行本地存储。相反,它位于一个远程服务器上,必须使用 Ajax 加载。因此,对于该存储,宣布代理对象,以将其作为 Ext.data.AjaxProxy 的实例。您可能已经显式创建了一个这样的对象,然后在存储对象的 config 对象(构造函数)中指定它,但是我们选择使用更惯用的 JavaScript,其方法为代理指定 config 对象。如需获得 AjaxProxy 实例,只需指定代理的类型属性,然后指定检索数据的 URL。
现在指定阅读器属性,它指定一个 Ext.data.Reader 实例。这是一个对象,用于处理来自服务器的原始数据并再将其转换成代理提供给存储的模型对象的实例。您可能已经在存储及其代理之前显式创建了 Reader 的实例,但是我们选择使用 JavaScript 对象,该对象将作为 config 输入以构造阅读器。要创建阅读器,告知它期望哪类数据 (JSON)、数据结构的根元素是什么、该模型的哪个属性将用作 ID。最后,配置存储为 autoLoad 数据,也就是说,尽可能地提取数据。现在已经创建了存储,并加载了为其提供支持的远程数据,可以使用该数据创建移动优化的用户界面。

为移动设备优化的 部件
Ext JS 一直以提供丰富的 UI 部件集而著称,这些部件由直观的、面向对象的一组 API 提供支持。Sencha Touch 延续了这一传统,但是包括了专为移动设备而设计的部件。对于我们的示例,您想创建某种类型的员工列表,该列表需要在移动设备上看起来美观,工作正常。Sencha Touch 提供 Ext.List 组件来满足这个常见用例。清单 3 展示了如何使用 List 组件显示该应用程序中的员工对象。

清单 3. 使用 List 组件

				
var list = new Ext.List({
    store        : store,
    tpl          : new Ext.XTemplate(
                   '<tpl for=".">',
                       '<div class="contact">',
                           '{firstName} <strong>{lastName}</strong>',
                       '</div>',
                   '</tpl>'
               ),
    itemSelector : 'div.contact',
    singleSelect : true,
    grouped      : true,
    indexBar     : true,
    floating     : true,
    width        : 350,
    height       : 370,
    centered     : true,
    modal        : true,
    hideOnMaskTap: false,
    fullscreen   : true
});

为 List 指定的第一件事是其存储属性将是什么。仅指定您在清单 2 中创建的 Store 实例,因为这将是数据源。下一步,指定其 tpl 属性或模板。tpl 将应用到来自存储的每个员工对象。Sencha Touch 包含简单的模板语言,用于创建包括动态数据元素的 HTML;它类似于 Java 服务器页面 (JSP)、PHP 或 Embedded Ruby (ERb) 模板。例如,如果有个员工的 firstName = 'John' 和 lastName = 'Smith',那么 清单 4 显示了上述 tpl 属性将产生的结果。

清单 4. 使用 Sencha Touch 模板生成的 HTML 示例

<div class="contact">
    John <strong>Smith</strong>
</div>

回到清单 3,要指定的下一个是 itemSelector 属性。这是一个 CSS 选择器,Sencha Touch 用它来确定当该组件发生事件时与哪个节点协同工作。您很快将看到 Sencha Touch 提供了许多您可以定制的有用的内置行为,但是,为了充分利用这些行为,您必须指定 itemSelector 属性。在这种情况下,您利用列表中的每个员工对象都将包含在带有类联系人的分段中这一事实。
多个其他属性在 config 对象中设置,该对象用于构造清单 3 中的 List 组件。这些大多数是简单的 UI 相关的属性。其他两个有趣的属性分别是 singleSelect 属性(一次是否能够选择列表中一个以上的项目)和 grouped 属性(列表中的项目是否应归组在一起;这被设置为 true)。清单 2 显示了如果为该分组指定一个函数 (getGroupString)。最后,请注意 indexBar 属性产生一个能够用于在列表周围跳动的索引。图 1 显示了列表在 iPhone 上的展示效果。

图 1. 员工目录应用程序的屏幕截图

如图 1 所示,它展示了如何执行分组操作以及如何显示索引栏,此列表看起来就像是 iPhone 的原生列表。图 2 显示了在广受欢迎的 Android 设备(三星 Galaxy S 手机)上运行的同一个应用程序。

图 2. 在 Android 手机上运行的应用程序

如图 2 所示,Sencha Touch 为 iOS 和 Android 设备创建了同样引人注目的 UI。图 2 显示的数据多于图 1 所示的数据,仅是因为 Android 设备使用的屏幕要比 iPhone 的屏幕大。否则,基本上相似。回到清单 1 中所注册的模型,请注意该应用存储的数据要多于列表视图所显示的。看一看如何创建用户能够从列表视图打开的详细的员工视图。

事件处理和模板
Sencha Touch 提供了许多特定于移动或触摸设备的便捷的事件,比如敲、击、手指缩放甚至旋转。对于该应用,您的目标是让用户能够在列表视图敲一个员工,并查看关于该员工的更多信息。清单 5 显示了如何实现这一目标。

清单 5. 打开详细信息面板

list.on('itemtap', function(dataView, index, item, e){
    var employee = dataView.store.data.items
.data; var template = new Ext.XTemplate( '<p>Name: {firstName} {lastName}</p>', '<p>Email: {email}</p>', '<p>Phone: {phone}</p>' ); var str = template.apply(employee); var panel = new Ext.Panel({ floating : true, width : 250, height : 155, centered : true, modal : false, hideOnMaskTap: false, dockedItems: [{ dock: 'top', xtype: 'toolbar', title: employee.firstName + ' ' + employee.lastName },{html:str}] }); var btn = new Ext.Button({ text: 'Close', ui: 'action', handler: function(){ panel.hide(); } }); panel.addDocked(btn); panel.show(); });

要处理敲事件,您只需使用列表的 on 函数来监听 itemtap 事件。Sencha Touch 中的所有 UI 组件都拥有一个这样的 on 函数,尽管您可以监听的事件列表根据不同的组件而不同。仅仅监听 itemtap 并输入函数 (closure),以在发生事件时执行该函数。该函数将传递 Ext.DataView 对象(Ext.List 的父类)、被敲的项目的索引、被敲的 UI 节点以及一个事件对象。在清单 5 中,dataView(即 List 组件)会检索对应于被敲的员工姓名的 Employee 对象。再次使用 Sencha Touch 的模板系统为该员工创建一些将显示其联系信息的 HTML。(请注意在这种情况下,您可使用该模板的 apply 方法直接创建 HTML。)接下来创建 Ext.Panel 对象,它是 Sencha Touch 中另一个常用的 UI 部件。在面板中创建一个标题栏和一个关闭按钮,并将这些对象与 HTML 模板一起堆叠在面板中。对于关闭按钮,指定一个只关闭该面板的处理函数。然后只显示该面板。图 3 显示了在 Android 手机上的画面。

图 3. Android 手机上的员工详细信息

您使用不到 100 行的 JavaScript 即创建了一个交互式移动 Web 应用程序,该程序使用 Ajax 加载远程数据。它在 iOS 和 Android 设备上都运行良好。您可以看到为什么人们对 Sencha Touch 非常感兴趣,那是因为它能够提供许多有用的功能,而无需不必要的样板代码。

结束语
本文研究了如何使用 Sencha Touch 作为一个完整的移动 Web 应用程序框架以及这样做的原因。本文考虑到了所有的相关事项,从检索数据到创建移动兼容的 UI 来处理触摸事件。Sencha Touch 提供了对应用开发人员非常友好的面向对象的编程范例。同时,它还充分利用了类似于 JavaScript 对象字面值 (object literal) 和闭包的强大功能。在如此新和不断发展的领域(移动 Web)中,该框架的成熟度和功能非常值得注意。在许多方面,Sencha Touch 已经快速成为衡量其他框架的金牌标准。

示例下载
http://www.ibm.com/developerworks/apps/download/index.jsp?contentid=832999&filename=sencha.zip&method=http&locale=zh_CN

作者:Michael Galpin
原文:http://www.ibm.com/developerworks/cn/web/wa-senchawebdev/