Sencha Touch 2 开发指南
一、Sencha Touch2简介
Sencha Touch是一个移动HTML5开发框架(以下简称ST),ST可以让你的Web App看起来像Native App。美丽的用户界面组件和丰富的数据管理,全部基于最新的HTML5和CSS3的 WEB标准,全面兼容Android和Apple iOS设备。
下面是ST官方给出的几点[color=red]优点[/color]:
1,基于最新的WEB标准 – HTML5,CSS3,JavaScript。
2,支持世界上最好的设备。兼容Android和iOS,Android上的开发人员还可以使用一些专为Android定制的主题。
3,增强的触摸事件。
4,数据集成。提供了强大的数据包,通过Ajax、JSONp、YQL等方式绑定到组件模板,写入本 地离线存储。,5
5,采用ExtJS4强大的类系统,使我们可以通过Javascript创建和继承已有的类,类系统提供了继承,依赖加载,强大的配置选项等内容。
二、开发入门
2.1 开发环境准备
开发环境不需要准备的太多,只需要:
Sencha touch2 SDK
一个支持HTML5的浏览器,推荐使用谷歌的Chrome和苹果的Safari
2.2 熟悉Sencha Touch2 SDK
先下载Sencha Touch框架
http://www.sencha.com/products/touch/
下面让我们看看下载的包里都有哪些东西。
将下载的sencha-touch开发包解压我们可以看到以下文件
mulujiegou
builds目录是打包过后的一些js文件。
command是ST自带的一些打包工具,例如将ST的原生态应用打包成支持androud设备的apk安装文件等。
docs是官方的api参考文档,需要部署在web容器中才可以查看。例如tomcat.
examples 是ST的官方实例,里面包含完整的源代码,基本包括了ST的所有组件及应用程式的开发样例,因此是学习ST的最佳文档。
Mircoloader是ST2一个重大的改进,类加载器,优化了ST组件的载入速度 。
Resources 是ST的一些资源文件,包括css样式、主题文件等,例如ST给我们提供了android、apple等常用移动设备平台的主题,开发中通常也需要引用此目录下的一些样式文件
Src是ST组件 的源代码。
以下几个是ST的核心库文件:
sencha-touch.js是包含了部分组件的一个库文件,它是经过压缩处理后的库文件。
sencha-touch-all.js则是包含了ST所有组件的库文件,通常在开发过程中也是引用此库文件。
sencha-touch-all-debug.js顾名思义是用来调试的,因为包含缩进,所以方便调试。
sencha-touch-debug.js也是用来调试用的。
2.3 框架的加载
至此我们已经了解了开发ST应用所需的环境,也了解了ST的官方SDK的一些情况,接下来就是如何在自己的项目中引用ST框架,开始您的ST开发之旅。
首先在您的html页面的head标签中间引入ST框架的css样式文件,js库文件,如:
hexing
注意:这里引入的css及js文件路径应根据自己的目录结构做相应的调整.
app.js 是我们自己定义的javascript文件,一般一个应用都有一个app.js文件作为应用的启动文件,在这里面会写一些关于应用启动加载的一些代码,具体的app.js如何去写将在稍后章节中详细阐述。接下来我们在来看看整个ST应用的一个目录结构是怎样的:例如:
app-sldfj
app 目录包含ST应用的控制器、模型、代理、数据存储器、视图、设备配置文件等,打开app目录如下:
app-file
controller对应ST应用的控制器,按照官方的MVC开发模式,所有的控制处理逻辑代码都应该在此目录之下,它类似J2EE开发中MVC模式的C,是集中控制应用程式的行为,model包含了一些模型定义文件,对应于MVC开发模式的M,它是应用程式需要用到的模型的定义,它的含义和J2EE开发中MVC模式的模型意义相似,profile是配置各个平台的一个启动配置文件,如果您的应用程式需要在不同的平台及不同的设备上运行,则可能需要在此配置每个设备平台的专属配置文件,例如在android、ios或者iPad等平台及设备上。
Proxy是和ST应用中数据交互密不可分的,它相当是一个数据获取的来源,充当代理获取数据的一个角色,store则是ST的一个核心部分,它是和所有数据存储有关的,view则是经典MVC模式中的V,它提供了应用程式中视图的部分,用来展现ST应用的UI部分,这样model 、view、controller就组成了ST应用的一个MVC模式,在ST2的官方文档及实例中都极力推荐采用MVC的模式来开发自己的应用,因为采用这样有一个好处,应用程式的数据、视图、行为控制分离,代码结构清晰,便于日后的维护,同样更适用于实现组件化开发。
2.4 ST应用开发模式之MVC
MVC结构是通常用的数据结构. 做起应用来也比较标准
M 数据模型:在应用程序中表示一种数据模型,比如一个电子商务应用程序可能会有用户、产品、订单等不同的数据模型
V 视图:负责将数据展示给用户,并扩充 Sencha Touch 的内置组件。(译者注:你可以理解为用户界面的一个个组成部分)
C 控制器:处理应用程序的交互,侦听用户的轻触、猛击(译者注:真实意思是长按?)等事件并做出相应的响应
S 数据存储器:负责把数据加载到你的应用并以列表(List)或者数据视图(DataView)等形式表现出来
P 设备配置:可以使你为平板电脑和手机等不同设备,轻易定制应用程序用户界面,并尽可能多的共享代码
Sencha touch2的mvc图示如下:
sendacha
对象通常是你开发一个ST应用时需要定义的第一个东西,类似下面这样子:
Ext.application({
name: 'MyApp',
models: ['User', 'Product', 'nested.Order'],
views: ['OrderList', 'OrderDetail', 'Main'],
controllers: ['Orders'],
launch: function() {
Ext.create('MyApp.view.Main');
}
});
如代码所示,[color=darkred]application 构造参数中有个name属性,它为你的应用程序创建一个唯一命名空间[/color],其下包含了该应用全部的 model、view、controller 还有其他 class(类),比如一个叫做 MyApp 的应用就应该遵循以下形式来组织:MyApp.model.User,MyApp.controller.Users,MyApp.view.Main等,这可以保证你整个的应用程序都处在一个唯一全局变量下,从而最大限度降低代码冲突的可能性。
应用程序会按照你在 application 构造函数中定义好的models,views和controllers属性成员来自动加载它们对应的 class(类)到当前应用,ST2 架构约定的文件结构如下:model 都放在 app/model 目录,controller 都放在 app/controller 目录,view 则放在 app/view 目录,比如app/model/User.js,app/controller/Orders.js,app/view/Main.js,这样应用程序就可以自动找到并加载这些类,通过这里就基本可以了解到ST应用其实就是一个html,一个app.js在加上分别处于app/model 、app/view 、app/controller之下的一堆model、view、controller文件。
除了遵循上述的常规命名格式以外,我们还可以使用完整类名的方式来定义这些配置,[color=darkred]换言之 application 构造函数中的 models、views、controllers 这些参数属性也都可以用完整类名方式来定义.[/color]
2.4.1 控制器
[color=green]Controller(控制器)就像胶水一样粘合出一个完整的应用程序,它们侦听UI界面触发的事件,然后做出相应的动作,还能够让我们的代码更简洁,可读性好,从而把界面逻辑和控制逻辑隔离开来。[/color]
假如你需要用户通过一个 login 表单来登录你的应用程序,此时的 view(视图)就是这个包含了所有字段和其他元素的表单,而它的 controller(控制器)要做的就是侦听表单提交按钮的点触事件并进行身份验证,[color=green]每次我们要处理数据或者状态的时候,这个ontroller(控制器)才是应该起作用的类,而不是 view(视图)[/color]。
Controller(控制器)通过一些简单的约定,展示了一套虽小但却很强大的特性。应用程序的每一个 controller(控制器)都是Ext.app.Controller 的一个子类,当然你也可以继承现有的 controller ,只要它也是继承自 Ext.app.Controller ,controller(控制器)都存在于 MyApp.controller.* 命名空间,例如你的应用有一个叫做 Sessions 的controller ,那么它的完整命名空间将会是MyApp.controller.Sessions 并且被定义在 app/controller/Sessions.js 文件中。
[color=green]每个 controller(控制器)都是 Ext.app.Controller 的一个子类,加载它的应用程序也只会对它实例化一次,应用程序自己会控制每个 controller(控制器)在同一时间[/color][color=red]只有一个实例[/color]。[color=brown]我们使用 Application 对象的 controllers 参数来加载 Controller(控制器)并且会自动实例化它们[/color]。
一个简单例子
这里将演示如何快速定义上面描述的 Sessions 控制器,[color=blue]我们将使用 controller 的两个配置参数,refs 和 control[/color] ,[color=brown]refs 是找到页面组件的简单方式[/color],这个例子里 controller(控制器)会搜索所有 formpanel 类型的控件,然后将找到的第一个赋值给 loginForm 属性,这个属性会在下面的 doLogin 方法中用到。
然后我们要做的是配置 control 参数,像 refs 一样使用 ComponentQuery 选择器来查找所有包含 button 控件的 formpanel 下的 button 控件,在本例中,将会得到我们登陆表单当中的提交按钮,任意一个符合此条件的 button 触发了tap事件,controller(控制器)都会去调用其中的 doLogin 函数。
Ext.define('MyApp.controller.Sessions', {
extend: 'Ext.app.Controller',
config: {
refs: {
loginForm: 'formpanel'
},
control: {
'formpanel button': {
tap: 'doLogin'
}
}
},
doLogin: function() {
var form = this.getLoginForm(),
values = form.getValues();
MyApp.authenticate(values);
}
});
doLogin 函数本身非常容易理解,由于我们前面定义了一个叫做 loginForm 的 ref ,controller(控制器)将会自动生成一个叫做 getLoginForm 的函数用来返回该 formpanel (也就是这个叫做 loginForm 的 ref 啦),待完成对这个 form 的引用之后,我们只需要把其中的值(用户名和密码)取出来然后传递给 authenticate(身份验证)函数即可,上述就是一个 controller(控制器)能做的绝大部分事情了 —— 侦听事件(通常由UI触发)然后做点别的什么事情,比如用户身份验证。
2.4.2 数据存储器
Store(数据存储器)是 ST 的重要组成部分,它能够实现大部分的组件数据绑定工作。[color=indigo]简单来说,一个 store(数据存储器)就是一个由 Model(数据模型)的实例组成的数组[/color],诸如 List 和 DataView 这类的数据绑定型控件,他们会为 Store(数据存储器)中的每一个 Model(数据模型)实例渲染一个 item(这里指数据绑定控件的子项),Store(数据存储器)中的 Model(数据模型)实例被添加或者删除的时候会触发数据绑定控件的相应事件,从而实现控件的更新。
Stores guide (数据存储器指南)网页上有更多信息,比如到底什么是 Store(数据存储器)以及它们在你的应用程序中是如何去与 Component(组件)协调工作的,那里还有几个你必须注意的特殊要点,均与 Application 实例有关。
2.4.3 设备配置文件
[color=darkred]ST 可以跨越非常广泛的平台,尽管这些平台拥有不同的性能和屏幕尺寸。一个在平板电脑上工作良好的UI并不一定适应手机界面,反之亦然。所以为不同设备提供定制过的不同[/color] view(视图)是一件很有必要的事情。毕竟谁也不想仅仅为了提供不同的 UI 就得把应用程序重写 N 次,[color=red]我们希望可以让不同设备共享尽可能多的代码。
Device Profile(设备配置)是一些简单的类,这些类能让你定义程序支持的不同类型设备以及如何处理这些不同[/color]。[color=brown]Device Profile(设备配置)不是必需的,你可以一开始不定义Profile 以后再添加,甚至永远不定义它们。每个 profile 都要定义一个简单的 isActive 函数,用来返回当前设备上是否应该启用此 profile(换言之,该 profile 是否匹配当前的设备) ,并为该 profile 载入一堆(当前 profile 中约定的)model ,view 和 controller 。[/color]
[color=brown]要为你的应用程序添加 Profile 支持功能,你只需告诉应用程序有哪些 profile 需要被支持,然后为它们各自创建Ext.app.Profile 的子类即可[/color]。
Ext.application({
name: 'MyApp',
profiles: ['Phone', 'Tablet']
});
如上面代码所示,应用程序会加载 app/profile/Phone.js 和 app/profile/Tablet.js 两个文件,我们假定平板电脑的版本将会拥有一些额外的能力,比如对组的管理功能,下面的例子将告诉我们该如何定义tablet的profile:
Ext.define('MyApp.profile.Tablet', {
extend: 'Ext.app.Profile',
config: {
controllers: ['Groups'],
views: ['GroupAdmin'],
models: ['MyApp.model.Group']
},
isActive: function() {
return Ext.os.is.Tablet;
}
});
[color=red]当ST检测到你的设备是一台平板电脑时,isActive 函数将会返回 true 。[/color]鉴于现在不断涌现出的各种新设备,其外形和尺寸已经越来越模糊了手机和平板电脑的界限,故而我们无法找到傻瓜化的方式去界定哪些设备是平板哪些设备是手机,ST 的 [color=brown]Ext.os.is.Tablet 只有在 iPad 上运行的时候将被设定为 true ,其他则为 false ,如果你需要更好的判断和控制,你可以通过在 isActive 函数中进行更多你希望的检测,来控制它返回 true 还是 false[/color] 。
你必须保证只有一个 profile 的 isActive 函数可以返回 true ,如果超过一个的话,只有第一个会有效而其他将被忽略,第一个返回 true 的 profile 将被视作应用程序的 currentProfile(当前 profile ),你也可以随时获取到当前 profile 的值。
[color=darkred]如果检测到的当前profile定义了额外的 model(数据模型)、view(视图)、controller(控制器)、store(数据存储器),它们会与 application 当中定义的其他元素一起被自动加载。[/color]而所有在 profile 中定义的元素路径前面都会被加上 profile 的名称,除非你对它们定义了完整路径的类名,如下所示。
views: [‘GroupAdmin’] 将会加载 app/view/tablet/GroupAdmin.js (因为 GroupAdmin 是在 tablet profile 中配置的)
controllers: [‘Groups’] 将会加载 app/controller/tablet/Groups.js (同上)
models: [‘MyApp.model.Group’] 将会加载 app/model/Group.js (因为使用了完整路径)
绝大多数情况下,profile 只会定义额外的 controller 和 view ,因为 model 和 store 一般情况下都会被共享。关于 profile 的更多细节,请访问 device profiles guide 页面(设备配置指南)。
[color=orange]2.4.4 应用启动[/color]
[color=red]每个 Application 对象都会定义一个 launch 函数,它将会在你应用程序所需的全部 class 加载完成,且应用程序已经做好准备的情况下执行[/color]。一般来说这里就是你用来放置应用程序启动逻辑的最好位置了,比如你可以在这里为你的应用创建主要 view 框架。
[color=red]除了 Application 中的 launch 函数之外,还有两个地方可以放置启动逻辑:第一,每个 controller(控制器)都可以定义一个 init 函数,这个函数将会运行在 application 的 launch 运行之前[/color];[color=darkred]第二,如果你使用了设备 profile ,每一个 profile 都可以定义一个 launch 函数,他将会在 controller(控制器)的 init 之后和 application 的 launch 之前被调用[/color]。
注意只有活动 profile 的 launch 函数才会被调用,比如你分别定义了 phone 和 tablet 的 profile ,现在是在 tablet 上运行它,那么只有 tablet profile 中的 launch 函数会被调用到。
[color=darkred]Controller 的 init 首先被调用
其次是当前 Profile 的 launch 被调用
然后 Application 的 launch 被调用
最后是其他 controller 的 launch 被调用[/color]
3.1.2 什么是容器
应用程序是由很多组件组成的,他们被一个个的组件包含着。容器也像组件,但除了组件的功能以外他还可以渲染和插入新的组件。[color=red]大部分App 都有唯一的一个最上层容器叫做”Viewport”,他占满了整个屏幕,子组件被包含在他们里面[/color]。
容器有下面几个功能:
在初始化和运行的时候添加新的组件
移除组件
指定组件布局
布局确定了组件在屏幕上的显示方式。ST提供了几种布局方式,可以方便开发者完成组件布局。
3.2 组件使用
3.2.1 初始化组件
组件的初始化和ST 中其他类的初始化一样。使用Ext.create 方法。
[color=darkred]3.2.2 配置组件
你可以通过configuration 选项对任意一个组件进行配置。所有的configuration 都在组件类的“Config Options”中。你可以在组件初始化时传入任意个配置选项,也可以在组件初始化之后对他的配置进行修改。
任何一个配置都有getter和Setter方法。他们是自动生成的[/color]。例如一个配置选项叫做“html”那么他将会有一个getHtml和setHtml方法一个默认的配置拥有一个getDefault 和setDefault方法。
3.2.3 使用ST已有的组件
ST中有两种方式用来创建组件,第一种是在config中通过xtype直接申明组件,第二种是通过Ext.create()方法创建组件。
Ext.define('NoticeApp.view.LoginViewport',{
extend:'Ext.Panel',
xtype:'loginviewport',
requires: [
'NoticeApp.view.SystemLogin'
],
config:{
items:[
{
id:'loginNavigationview',
xtype:'navigationview',
navigationBar:false,
items:[
{
xtype:'systemlogin'
}
]
}
]
},
initialize: function(){
//to do something
}
});
如上面示例代码中的红色部分,通过xtype navigationview申明了一个 navigationview 导航视图组件。
而绿色标记部分则通过xtype systemlogin 申明了一个组件,请注意 systemlogin这个组件或则说是视图在标准的ST组件中并没有找到,是因为这是一个自定义的组件或者说是视图,关于自定义组件将在下一节中讲述。
下面是通过Ext.create方法创建组件
Ext.create('NoticeApp.view.MainViewport',{
fullscreen: true,
layout: 'card'
});
这一段示例代码中通过Ext.create方法创建了一个类为NoticeApp.view.MainViewport的组件,同样MainViewport这个视图是自定义的视图,通常在ST开发中,我们需要去继承已有的组件类来扩展或者自定义自己的视图,这样符合MVC的开发模式,通过将各种组件通过一定的布局方式粘合在一期形成自己的视图组件,也为实现组件复用奠定了基础。
一、Sencha Touch2简介
Sencha Touch是一个移动HTML5开发框架(以下简称ST),ST可以让你的Web App看起来像Native App。美丽的用户界面组件和丰富的数据管理,全部基于最新的HTML5和CSS3的 WEB标准,全面兼容Android和Apple iOS设备。
下面是ST官方给出的几点[color=red]优点[/color]:
1,基于最新的WEB标准 – HTML5,CSS3,JavaScript。
2,支持世界上最好的设备。兼容Android和iOS,Android上的开发人员还可以使用一些专为Android定制的主题。
3,增强的触摸事件。
4,数据集成。提供了强大的数据包,通过Ajax、JSONp、YQL等方式绑定到组件模板,写入本 地离线存储。,5
5,采用ExtJS4强大的类系统,使我们可以通过Javascript创建和继承已有的类,类系统提供了继承,依赖加载,强大的配置选项等内容。
二、开发入门
2.1 开发环境准备
开发环境不需要准备的太多,只需要:
Sencha touch2 SDK
一个支持HTML5的浏览器,推荐使用谷歌的Chrome和苹果的Safari
2.2 熟悉Sencha Touch2 SDK
先下载Sencha Touch框架
http://www.sencha.com/products/touch/
下面让我们看看下载的包里都有哪些东西。
将下载的sencha-touch开发包解压我们可以看到以下文件
mulujiegou
builds目录是打包过后的一些js文件。
command是ST自带的一些打包工具,例如将ST的原生态应用打包成支持androud设备的apk安装文件等。
docs是官方的api参考文档,需要部署在web容器中才可以查看。例如tomcat.
examples 是ST的官方实例,里面包含完整的源代码,基本包括了ST的所有组件及应用程式的开发样例,因此是学习ST的最佳文档。
Mircoloader是ST2一个重大的改进,类加载器,优化了ST组件的载入速度 。
Resources 是ST的一些资源文件,包括css样式、主题文件等,例如ST给我们提供了android、apple等常用移动设备平台的主题,开发中通常也需要引用此目录下的一些样式文件
Src是ST组件 的源代码。
以下几个是ST的核心库文件:
sencha-touch.js是包含了部分组件的一个库文件,它是经过压缩处理后的库文件。
sencha-touch-all.js则是包含了ST所有组件的库文件,通常在开发过程中也是引用此库文件。
sencha-touch-all-debug.js顾名思义是用来调试的,因为包含缩进,所以方便调试。
sencha-touch-debug.js也是用来调试用的。
2.3 框架的加载
至此我们已经了解了开发ST应用所需的环境,也了解了ST的官方SDK的一些情况,接下来就是如何在自己的项目中引用ST框架,开始您的ST开发之旅。
首先在您的html页面的head标签中间引入ST框架的css样式文件,js库文件,如:
hexing
注意:这里引入的css及js文件路径应根据自己的目录结构做相应的调整.
app.js 是我们自己定义的javascript文件,一般一个应用都有一个app.js文件作为应用的启动文件,在这里面会写一些关于应用启动加载的一些代码,具体的app.js如何去写将在稍后章节中详细阐述。接下来我们在来看看整个ST应用的一个目录结构是怎样的:例如:
app-sldfj
app 目录包含ST应用的控制器、模型、代理、数据存储器、视图、设备配置文件等,打开app目录如下:
app-file
controller对应ST应用的控制器,按照官方的MVC开发模式,所有的控制处理逻辑代码都应该在此目录之下,它类似J2EE开发中MVC模式的C,是集中控制应用程式的行为,model包含了一些模型定义文件,对应于MVC开发模式的M,它是应用程式需要用到的模型的定义,它的含义和J2EE开发中MVC模式的模型意义相似,profile是配置各个平台的一个启动配置文件,如果您的应用程式需要在不同的平台及不同的设备上运行,则可能需要在此配置每个设备平台的专属配置文件,例如在android、ios或者iPad等平台及设备上。
Proxy是和ST应用中数据交互密不可分的,它相当是一个数据获取的来源,充当代理获取数据的一个角色,store则是ST的一个核心部分,它是和所有数据存储有关的,view则是经典MVC模式中的V,它提供了应用程式中视图的部分,用来展现ST应用的UI部分,这样model 、view、controller就组成了ST应用的一个MVC模式,在ST2的官方文档及实例中都极力推荐采用MVC的模式来开发自己的应用,因为采用这样有一个好处,应用程式的数据、视图、行为控制分离,代码结构清晰,便于日后的维护,同样更适用于实现组件化开发。
2.4 ST应用开发模式之MVC
MVC结构是通常用的数据结构. 做起应用来也比较标准
M 数据模型:在应用程序中表示一种数据模型,比如一个电子商务应用程序可能会有用户、产品、订单等不同的数据模型
V 视图:负责将数据展示给用户,并扩充 Sencha Touch 的内置组件。(译者注:你可以理解为用户界面的一个个组成部分)
C 控制器:处理应用程序的交互,侦听用户的轻触、猛击(译者注:真实意思是长按?)等事件并做出相应的响应
S 数据存储器:负责把数据加载到你的应用并以列表(List)或者数据视图(DataView)等形式表现出来
P 设备配置:可以使你为平板电脑和手机等不同设备,轻易定制应用程序用户界面,并尽可能多的共享代码
Sencha touch2的mvc图示如下:
sendacha
对象通常是你开发一个ST应用时需要定义的第一个东西,类似下面这样子:
Ext.application({
name: 'MyApp',
models: ['User', 'Product', 'nested.Order'],
views: ['OrderList', 'OrderDetail', 'Main'],
controllers: ['Orders'],
launch: function() {
Ext.create('MyApp.view.Main');
}
});
如代码所示,[color=darkred]application 构造参数中有个name属性,它为你的应用程序创建一个唯一命名空间[/color],其下包含了该应用全部的 model、view、controller 还有其他 class(类),比如一个叫做 MyApp 的应用就应该遵循以下形式来组织:MyApp.model.User,MyApp.controller.Users,MyApp.view.Main等,这可以保证你整个的应用程序都处在一个唯一全局变量下,从而最大限度降低代码冲突的可能性。
应用程序会按照你在 application 构造函数中定义好的models,views和controllers属性成员来自动加载它们对应的 class(类)到当前应用,ST2 架构约定的文件结构如下:model 都放在 app/model 目录,controller 都放在 app/controller 目录,view 则放在 app/view 目录,比如app/model/User.js,app/controller/Orders.js,app/view/Main.js,这样应用程序就可以自动找到并加载这些类,通过这里就基本可以了解到ST应用其实就是一个html,一个app.js在加上分别处于app/model 、app/view 、app/controller之下的一堆model、view、controller文件。
除了遵循上述的常规命名格式以外,我们还可以使用完整类名的方式来定义这些配置,[color=darkred]换言之 application 构造函数中的 models、views、controllers 这些参数属性也都可以用完整类名方式来定义.[/color]
2.4.1 控制器
[color=green]Controller(控制器)就像胶水一样粘合出一个完整的应用程序,它们侦听UI界面触发的事件,然后做出相应的动作,还能够让我们的代码更简洁,可读性好,从而把界面逻辑和控制逻辑隔离开来。[/color]
假如你需要用户通过一个 login 表单来登录你的应用程序,此时的 view(视图)就是这个包含了所有字段和其他元素的表单,而它的 controller(控制器)要做的就是侦听表单提交按钮的点触事件并进行身份验证,[color=green]每次我们要处理数据或者状态的时候,这个ontroller(控制器)才是应该起作用的类,而不是 view(视图)[/color]。
Controller(控制器)通过一些简单的约定,展示了一套虽小但却很强大的特性。应用程序的每一个 controller(控制器)都是Ext.app.Controller 的一个子类,当然你也可以继承现有的 controller ,只要它也是继承自 Ext.app.Controller ,controller(控制器)都存在于 MyApp.controller.* 命名空间,例如你的应用有一个叫做 Sessions 的controller ,那么它的完整命名空间将会是MyApp.controller.Sessions 并且被定义在 app/controller/Sessions.js 文件中。
[color=green]每个 controller(控制器)都是 Ext.app.Controller 的一个子类,加载它的应用程序也只会对它实例化一次,应用程序自己会控制每个 controller(控制器)在同一时间[/color][color=red]只有一个实例[/color]。[color=brown]我们使用 Application 对象的 controllers 参数来加载 Controller(控制器)并且会自动实例化它们[/color]。
一个简单例子
这里将演示如何快速定义上面描述的 Sessions 控制器,[color=blue]我们将使用 controller 的两个配置参数,refs 和 control[/color] ,[color=brown]refs 是找到页面组件的简单方式[/color],这个例子里 controller(控制器)会搜索所有 formpanel 类型的控件,然后将找到的第一个赋值给 loginForm 属性,这个属性会在下面的 doLogin 方法中用到。
然后我们要做的是配置 control 参数,像 refs 一样使用 ComponentQuery 选择器来查找所有包含 button 控件的 formpanel 下的 button 控件,在本例中,将会得到我们登陆表单当中的提交按钮,任意一个符合此条件的 button 触发了tap事件,controller(控制器)都会去调用其中的 doLogin 函数。
Ext.define('MyApp.controller.Sessions', {
extend: 'Ext.app.Controller',
config: {
refs: {
loginForm: 'formpanel'
},
control: {
'formpanel button': {
tap: 'doLogin'
}
}
},
doLogin: function() {
var form = this.getLoginForm(),
values = form.getValues();
MyApp.authenticate(values);
}
});
doLogin 函数本身非常容易理解,由于我们前面定义了一个叫做 loginForm 的 ref ,controller(控制器)将会自动生成一个叫做 getLoginForm 的函数用来返回该 formpanel (也就是这个叫做 loginForm 的 ref 啦),待完成对这个 form 的引用之后,我们只需要把其中的值(用户名和密码)取出来然后传递给 authenticate(身份验证)函数即可,上述就是一个 controller(控制器)能做的绝大部分事情了 —— 侦听事件(通常由UI触发)然后做点别的什么事情,比如用户身份验证。
2.4.2 数据存储器
Store(数据存储器)是 ST 的重要组成部分,它能够实现大部分的组件数据绑定工作。[color=indigo]简单来说,一个 store(数据存储器)就是一个由 Model(数据模型)的实例组成的数组[/color],诸如 List 和 DataView 这类的数据绑定型控件,他们会为 Store(数据存储器)中的每一个 Model(数据模型)实例渲染一个 item(这里指数据绑定控件的子项),Store(数据存储器)中的 Model(数据模型)实例被添加或者删除的时候会触发数据绑定控件的相应事件,从而实现控件的更新。
Stores guide (数据存储器指南)网页上有更多信息,比如到底什么是 Store(数据存储器)以及它们在你的应用程序中是如何去与 Component(组件)协调工作的,那里还有几个你必须注意的特殊要点,均与 Application 实例有关。
2.4.3 设备配置文件
[color=darkred]ST 可以跨越非常广泛的平台,尽管这些平台拥有不同的性能和屏幕尺寸。一个在平板电脑上工作良好的UI并不一定适应手机界面,反之亦然。所以为不同设备提供定制过的不同[/color] view(视图)是一件很有必要的事情。毕竟谁也不想仅仅为了提供不同的 UI 就得把应用程序重写 N 次,[color=red]我们希望可以让不同设备共享尽可能多的代码。
Device Profile(设备配置)是一些简单的类,这些类能让你定义程序支持的不同类型设备以及如何处理这些不同[/color]。[color=brown]Device Profile(设备配置)不是必需的,你可以一开始不定义Profile 以后再添加,甚至永远不定义它们。每个 profile 都要定义一个简单的 isActive 函数,用来返回当前设备上是否应该启用此 profile(换言之,该 profile 是否匹配当前的设备) ,并为该 profile 载入一堆(当前 profile 中约定的)model ,view 和 controller 。[/color]
[color=brown]要为你的应用程序添加 Profile 支持功能,你只需告诉应用程序有哪些 profile 需要被支持,然后为它们各自创建Ext.app.Profile 的子类即可[/color]。
Ext.application({
name: 'MyApp',
profiles: ['Phone', 'Tablet']
});
如上面代码所示,应用程序会加载 app/profile/Phone.js 和 app/profile/Tablet.js 两个文件,我们假定平板电脑的版本将会拥有一些额外的能力,比如对组的管理功能,下面的例子将告诉我们该如何定义tablet的profile:
Ext.define('MyApp.profile.Tablet', {
extend: 'Ext.app.Profile',
config: {
controllers: ['Groups'],
views: ['GroupAdmin'],
models: ['MyApp.model.Group']
},
isActive: function() {
return Ext.os.is.Tablet;
}
});
[color=red]当ST检测到你的设备是一台平板电脑时,isActive 函数将会返回 true 。[/color]鉴于现在不断涌现出的各种新设备,其外形和尺寸已经越来越模糊了手机和平板电脑的界限,故而我们无法找到傻瓜化的方式去界定哪些设备是平板哪些设备是手机,ST 的 [color=brown]Ext.os.is.Tablet 只有在 iPad 上运行的时候将被设定为 true ,其他则为 false ,如果你需要更好的判断和控制,你可以通过在 isActive 函数中进行更多你希望的检测,来控制它返回 true 还是 false[/color] 。
你必须保证只有一个 profile 的 isActive 函数可以返回 true ,如果超过一个的话,只有第一个会有效而其他将被忽略,第一个返回 true 的 profile 将被视作应用程序的 currentProfile(当前 profile ),你也可以随时获取到当前 profile 的值。
[color=darkred]如果检测到的当前profile定义了额外的 model(数据模型)、view(视图)、controller(控制器)、store(数据存储器),它们会与 application 当中定义的其他元素一起被自动加载。[/color]而所有在 profile 中定义的元素路径前面都会被加上 profile 的名称,除非你对它们定义了完整路径的类名,如下所示。
views: [‘GroupAdmin’] 将会加载 app/view/tablet/GroupAdmin.js (因为 GroupAdmin 是在 tablet profile 中配置的)
controllers: [‘Groups’] 将会加载 app/controller/tablet/Groups.js (同上)
models: [‘MyApp.model.Group’] 将会加载 app/model/Group.js (因为使用了完整路径)
绝大多数情况下,profile 只会定义额外的 controller 和 view ,因为 model 和 store 一般情况下都会被共享。关于 profile 的更多细节,请访问 device profiles guide 页面(设备配置指南)。
[color=orange]2.4.4 应用启动[/color]
[color=red]每个 Application 对象都会定义一个 launch 函数,它将会在你应用程序所需的全部 class 加载完成,且应用程序已经做好准备的情况下执行[/color]。一般来说这里就是你用来放置应用程序启动逻辑的最好位置了,比如你可以在这里为你的应用创建主要 view 框架。
[color=red]除了 Application 中的 launch 函数之外,还有两个地方可以放置启动逻辑:第一,每个 controller(控制器)都可以定义一个 init 函数,这个函数将会运行在 application 的 launch 运行之前[/color];[color=darkred]第二,如果你使用了设备 profile ,每一个 profile 都可以定义一个 launch 函数,他将会在 controller(控制器)的 init 之后和 application 的 launch 之前被调用[/color]。
注意只有活动 profile 的 launch 函数才会被调用,比如你分别定义了 phone 和 tablet 的 profile ,现在是在 tablet 上运行它,那么只有 tablet profile 中的 launch 函数会被调用到。
[color=darkred]Controller 的 init 首先被调用
其次是当前 Profile 的 launch 被调用
然后 Application 的 launch 被调用
最后是其他 controller 的 launch 被调用[/color]
3.1.2 什么是容器
应用程序是由很多组件组成的,他们被一个个的组件包含着。容器也像组件,但除了组件的功能以外他还可以渲染和插入新的组件。[color=red]大部分App 都有唯一的一个最上层容器叫做”Viewport”,他占满了整个屏幕,子组件被包含在他们里面[/color]。
容器有下面几个功能:
在初始化和运行的时候添加新的组件
移除组件
指定组件布局
布局确定了组件在屏幕上的显示方式。ST提供了几种布局方式,可以方便开发者完成组件布局。
3.2 组件使用
3.2.1 初始化组件
组件的初始化和ST 中其他类的初始化一样。使用Ext.create 方法。
[color=darkred]3.2.2 配置组件
你可以通过configuration 选项对任意一个组件进行配置。所有的configuration 都在组件类的“Config Options”中。你可以在组件初始化时传入任意个配置选项,也可以在组件初始化之后对他的配置进行修改。
任何一个配置都有getter和Setter方法。他们是自动生成的[/color]。例如一个配置选项叫做“html”那么他将会有一个getHtml和setHtml方法一个默认的配置拥有一个getDefault 和setDefault方法。
3.2.3 使用ST已有的组件
ST中有两种方式用来创建组件,第一种是在config中通过xtype直接申明组件,第二种是通过Ext.create()方法创建组件。
Ext.define('NoticeApp.view.LoginViewport',{
extend:'Ext.Panel',
xtype:'loginviewport',
requires: [
'NoticeApp.view.SystemLogin'
],
config:{
items:[
{
id:'loginNavigationview',
xtype:'navigationview',
navigationBar:false,
items:[
{
xtype:'systemlogin'
}
]
}
]
},
initialize: function(){
//to do something
}
});
如上面示例代码中的红色部分,通过xtype navigationview申明了一个 navigationview 导航视图组件。
而绿色标记部分则通过xtype systemlogin 申明了一个组件,请注意 systemlogin这个组件或则说是视图在标准的ST组件中并没有找到,是因为这是一个自定义的组件或者说是视图,关于自定义组件将在下一节中讲述。
下面是通过Ext.create方法创建组件
Ext.create('NoticeApp.view.MainViewport',{
fullscreen: true,
layout: 'card'
});
这一段示例代码中通过Ext.create方法创建了一个类为NoticeApp.view.MainViewport的组件,同样MainViewport这个视图是自定义的视图,通常在ST开发中,我们需要去继承已有的组件类来扩展或者自定义自己的视图,这样符合MVC的开发模式,通过将各种组件通过一定的布局方式粘合在一期形成自己的视图组件,也为实现组件复用奠定了基础。