Sencha 和 Sencha Touch 简介
Sencha 的前身是 ExtJS, 2010 年 ExtJS 改名为 Sencha。 ExtJS 是一个基于 JavaScript 编写的 Ajax 框架,它功能强大,界面美观,是基于 Ajax,DHTML,DOM 等技术开发 web 应用的一个非常成熟的框架。
Sencha Touch 是 ExtJS 整合 JQTouch、Raphaël 库而推出的适用于最前沿 Touch web 的框架,它是世界上第一个基于 HTML5 的 Mobile web 应用框架。Sencha Touch 框架可以让用户开发的 web 应用看起来像本地应用,它提供的绚丽的用户界面组件和丰富的数据管理功能全部都基于最新的 HTML5 和 CSS3 的 web 标准,并且全面兼容 Android 和 Apple iOS 等设备。
ExtJS 是为 web 开发人员提供的基于 JavaScript 和 web 标准快速构建可以跨浏览器平台运行的强大的 web 应用程序开发框架。它提供了丰富的用户界面组件和完善的文档资源,并且还有一个最重要的优势就是组件的设计简洁而容易扩展。
Ext GWT 是使用 Java 构建富 web 应用的最快,最有效的框架。它提供了运行性能良好的用户界面控件,并且在界面布局管理和全键盘支持方面有更突出的优势。
Ext Core 是一个构建跨浏览器运行的动态 web 应用的 JavaScript 库,它提供了 DOM 查询和元素选择的跨浏览器访问 API,它是一个轻量级的,运行性能良好并且很容易使用的 JavaScript 库。
Ext Designer 是一个帮助用户更快的创建桌面应用程序的可视化的界面图形化工具。
Sencha Touch 是第一个基于 HTML5 的 Mobile web 应用开发框架。
Sencha Animator 是一个创建基于 WebKit 浏览器和触屏移动设备运行的 CSS3 动画的工具,用户可以通过它创建出令人惊叹的动画,效果一点也不逊色于 Adobe 的动画工具。
Sencha Touch 的出现是 Mobile web 开发人员的福音,它提供的众多吸引人的特性让它成为目前业界最炙手可热的框架。
Sencha Touch 是 HTML5 Mobile 应用领域的领头羊,是目前为止最强大的移动平台开发框架,它把自己定位为框架而不是类库。随着 Mobile web 应用市场的扩大,Sencha Touch 还在不断的改进和完善中,不久的将来它还会提供更多的功能和更完善的设备支持。
用户界面组件,容器和布局组件
Sencha Touch 提供了丰富的用户界面组件,包括常用的按钮,单选框,复选框,文本框,日期选择控件,表格,列表等等,通过运用 Sencha Touch 定制的样式和主题,这些控件在移动设备上看起来和本地应用的 UI 组件没有什么区别。在容器和布局方面,Sencha Touch 也可以和 Adobe 的 Flex 相媲美,不仅提供了基础的 HBoxLayout,VBoxLayout 还提供了 DockLayout,CardLayout,FieldLayout 等更适合开发支持触屏设备的 Mobile web 应用的组件,关于每个组件详细的内容可以参考参考资源中列出的 Sencha Touch 的 API 文档。本文的最后一小节提供了一个工程代码示例,该工程主要使用了 Sencha Touch 提供的布局和用户界面组件构建了一个简单的 Mobile web 应用,代码中包含了关于所使用的用户组件的详细注释。
WebKit/CSS3 样式技巧增强
Sencha Touch 充分运用了 CSS3 的新特性使基于 webKit 浏览器运行的 Sencha Touch 应用更炫更酷。它支持并增强了对 Animations(动画),Transitions(转换效果),Gradients(渐变),shadows(阴影效果),Font Face(用户自定义字库),Marquee(文字移动效果),Multiple Backgrounds(多背景),RGBA(高清色彩显示通道)等样式效果的展示。
数据包
Sencha Touch 的一个最大特性就是提供了功能强大的数据包。在 Ext.data 包中提供了丰富的 API 实现对 AJAX,JSONP,YQL 等数据访问方式的支持,并提供了 API 供用户更简单方便的操作和展现 JSON 数据, XML 数据等。用户还可以扩展基础接口实现对更复杂数据的操作和访问。
Ext.data 数据包中最基础的是 Ext.data.Model,它就像 Java 的 Object 类一样是定义所有对象的基础类,代表应用程序中的数据类型:用户,产品,销售等任何东西。清单 1 是一个定义产品模型的代码片段。
//Ext.regModel 告诉 Sencha Touch 使用设置的字段创建一个新的模型 , 可以在以后通过名称 // 引用这个模型来轻松地配置组件加载的产品数据 Ext.regModel('Product', { fields: [ {name: 'name', type: 'string'}, {name: 'description', type: 'string'}, {name: 'price', type: 'float'}, {name: 'image_url', type: 'string'}, {name: 'in_stock', type: 'boolean'} ] }); |
创建好数据模型后,就可以创建用来展示数据的 Ext.DataView,DataView 提供了如何获取数据和展现数据的功能,每个 DataView 至少需要包涵一个 Ext.data.Store 和一个 Ext.XTemplate 类,Stores 是模型的实例集合,它通过代理类载入数据,代理类定义了数据的获取方式和数据类型,它还提供了一个 Reader 告诉代理类从服务器加载数据时如何解码得到的数据流。Ext.XTemplate 定义数据展现的方式,它是一个强大的模板类,一旦 Stores 加载了数据,DataView 会自动将每一个加载完毕的记录在模板的基础上渲染出 HTML 展现给用户。清单 2 是一个 DataView 定义样例:
//store 定义获取数据的方式(用 ajax 代理获取 URL 为‘ /product.json ’的数据)和数据类型 //(Product),XTemplate 定义数据展现的方式 //store 定义获取数据的方式和数据类型,XTemplate 定义数据展现的方式 var productsList = new Ext.DataView({ store: new Ext.data.Store({ model: 'Product', // 代理类的定义 proxy: { // 代理类型是 ajax type: 'ajax', // 数据来源 url : '/products.json', // 数据是 Json 格式 reader: { type: 'json', root: 'products' } } }), tpl: new Ext.XTemplate( '<tpl for=".">', '<div>', '<img src="{image_url}" />', '<div class="button">Buy</div>', '</div>', '</tpl>' ), fullscreen: true }); |
清单 2 中请求的 products.json 文件内容如清单 3 所示,它是一组 Json 对象,当使用 ajax 代理获取该文件的时候会返回一个 Json 对象的数组。
{ "products": [ {"name": "Some Product", "price": 9.99, "image_url": "product1.jpg", "in_stock": true }, {"name": "Another Product", "price": 7.50, "image_url": "product2.jpg", "in_stock": true }, {"name": "A third product", "price": 2.35, "image_url": "product3.jpg", "in_stock": false }, ... ] } |
DataView 还提供了一组事件供用户监听,包括数据选择,拖拽等信息,用户可以根据监听到的不同事件做相应的操作。清单 4 是监听 DataView 事件的代码示例。
productsList.on('itemtap', function (dataview, index, el, e) { // ‘ itemtap'事件将会在用户点击了’ buy ‘按钮后出发 if (e.getTarget('div.button')) { var product = dataview.store.getAt(index); //something need to implement for buy the product } }); |
数据验证和数据关联
Sencha Touch 提供了五种基本的数据验证方式,用户可以将验证方式的定义直接和对象的定义绑定,就像定义数据库表的列约束一样方便和简洁。这五种验证方式是:
Presence 验证数据不能为空值。
Length 验证数据的长度,可以定义最大长度和最小长度。
Format 验证数据的格式是否符合预定义的格式,比如定义某个时间属性的格式是“yyyy-mm-dd”,那么“20110324”这样的值就被认为是不合法的。
Inclusion 验证数据是否属于某个预定义的范围,该范围可以是一个闭合区间,也可以是一些可能值的集合。
Exclusion 验证数据是否不属于某个预定义的范围。
清单 5 是一个包含数据验证定义的 Product 模型定义。
// 定一个 SampleApp 的命名空间 Ext.ns('SampleApp'); SampleApp.Product = Ext.regModel('Product', { fields: [ {name: 'id', type: 'int'}, {name: 'user_id', type: 'int'}, {name: 'name', type: 'string'}, {name: 'price', type: 'float'}, {name: 'sku', type: 'string'} ], validations: [ //name 属性是必须的 {type: 'presence', name: 'name'}, //sku 属性的格式必须是 4 个数字后面至少有一个字母 {type: 'format', name: 'sku', matcher: /[0-9]{4}[A-Z]+/}, //name 属性的长度至少为 3 {type: 'length', name: 'name', min: 3} ], proxy: { type: 'localstorage', id : 'products' } }); |
定义了模型的数据验证内容后,我们就可以运用 Sencha Touch 提供的数据验证 API 对模型对象进行验证,清单 6 定义了一个具体的 Product 对象,并对对象进行验证。
// 创建了一个 Product 对象 var product = new SampleApp.Product({ name : 'Sencha Touch', sku : 'not a valid sku', price: 99 }); // 调用 validate 方法返回验证错误信息 var errors = product.validate(); errors.isValid()) // 返回“false”因为 sku 属性有错 errors.items; // 返回一个包涵该对象所有验证错误信息的数组 errors.forField('sku'); // 返回’ sku ‘属性的验证错误信息 |
validate() 方法是数据验证 API 的核心方法,调用 validate() 方法后会对所有的 Validation 定义自动进行验证并返回一个 Ext.data.Errors 对象。
数据库中的表关联关系大家都很熟悉,通过定义主键外键可以定义两个表的关联关系。Sencha Touch 支持类似于数据库表关联关系的基于对象的关联关系定义,通过 associations 关键字,用户可以在对象的定义中包涵对象关联关系的定义,目前支持两种关联关系:“hasMany”和“belongsTo”,用户可以自己扩展实现“one-two-many”,“one-to-one”等其他关联关系。清单 7 展示了如何定义用户和产品之间的“hasMany”和“belongsTo”关系。
SampleApp.User = Ext.regModel('User', { fields: [ {name: 'id', type: 'int'}, {name: 'name', type: 'string'}, {name: 'gender', type: 'string'}, {name: 'username', type: 'string'} ], validations: [ {type: 'inclusion', name: 'gender', list: ['male', 'female']}, {type: 'exclusion', name: 'username', list: ['admin']} ], associations: [ {type: 'hasMany', model: 'Product', name: 'products'} ], proxy: { type: 'localstorage', id : 'users' } }); SampleApp.Product = Ext.regModel('Product', { // 定义 Product 的属性和数据验证 ... associations: [ {type: 'belongsTo', model: 'User'} ] }); |
定义了对象之间的关系之后,就可以使用 Sencha Touch 提供的 API 进行关联数据的加载,同步等操作,清单 8 是关联数据操作的代码示例。
var user = new SampleApp.User({id: 10}); // 加载所有用户 id=10 的产品 user.products().load({ callback: function (records, operation) { alert(records.length); } }); // 给 id=10 的用户增加一个产品 user.products().add({ name: 'Ext JS 4.0', sku : '1234A' }); // 调用 sync 方法将通过用户关联关系增加的产品添加到产品列表 user.products().sync(); |