本文已添加至Sencha Touch 2快速入门系列索引:http://blog.csdn.net/ardy_c/article/details/7544470
转载请注明出处:http://blog.csdn.net/ardy_c/article/details/8543598
http://blog.csdn.net/ardy_c/article/details/8543598
控制器(Controller)
在Application中,控制器 (Controller) 负责监听用户的点击、滑动屏幕或其它等这些事件的发生,并调用相应的model来进行响应。例如,你的app中有一个登出按钮。控制器就是监听这个按钮的点击事件,并调用相应的方法对点击事件进行响应。当视图类 (View Class) 负责处理数据的显示、模型类 (Model Class) 负责处理加载和保存数据的时候,控制器类 (Controller Class) 就如粘合剂一样将视图和模型粘在一起。
与 Ext.app.Application的关系
控制器存在于Application的上下文中。一个Application通常由多个控制器构成,每一个控制器负责操作app指定的一部分。例如,一个负责处理网上购物订单的应用,可能有处理以下三种内容的控制器:订单、客户和产品。
如何使用控制器?Application使用的全部控制器都是通过在其config 属性中指定的。Application 会自动为其初始化并进行关联,所以在大部分情况下,你无需直接去初始化控制器。按照惯例,控制器的命名规则是使用它所管理的实体(通常是模型)的复数进行命名。例如,如果你的app叫作'MyApp',而你有一个控制器是管理产品 (Products) 的,惯例是创建一个 MyApp.controller.Products 类,并放在 app/controller/Products.js 路径中(路径信息可参与第一节中所展示的,sencha touch 2会将MyApp 定位到 app 目录下,而类名中的 controller.Products,会定位到 controller/Products.js 这个文件)。
在启动中
在 Application 启动的过程中,有四个主要的步骤,其中两个是属于控制器的。第一个,每一个控制器都可以定义一个初始化函数,该函数将会在调用 Application 启动函数前被调用。第二个,在 Application 和 Profile(配置,这里的profile是指device profile,用于为不同设备配置不同的响应视图) 的启动函数被调用后,作为启动过程的最后一个步骤,控制器的启动函数将会被调用。顺序如下:
1. 控制器 -- 调用控制器的初始化函数;
2. Profile -- 调用Profile的启动函数;
3. Application -- 调用Application的启动函数;
4. Controller -- 调用控制器的启动函数。
大多数情况下,你只需要将你的控制器指定的启动逻辑放到启动函数就可以了。因为控制器的启动函数将会在Application和Profile启动函数已被执行后再调用,你的app的界面初始化也将在这个时间点上进行。如果你需要在app启动前对控制器进行一些指定的处理,你可以实现控制器的初始化函数(init function)。
Refs和Control(配置属性)
控制器的中心就是一对配置属性:refs 和 control。他们被用于获取到app内部组件的关联,以及响应这些组件所产生的事件。以下我们先来看看refs配置属性。
Refs
Refs 依靠强大的 ComponentQuery 语法,可以很容易地定位到我们页面中的组件。在每一个控制器中,我们可以根据自身的需求定义refs的数量。例如,在下面的例子中,我们定义了一个 ref 叫 'nav' ,用于查找页面中一个 ID 为 ‘mainNav’ 的组件。然后,我们在后面的 addLogoutButton 函数中使用这个 refs 。请看下面的例子:
- Ext.define('MyApp.controller.Main', {
- extend: 'Ext.app.Controller',
- config: {
- refs: {
- nav: '#mainNav'
- }
- },
- addLogoutButton: function() {
- this.getNav().add({
- text: 'Logout'
- });
- }
- });
如平常一样,一个 ref 就是一对 key / value -- key (在这个例子中就是 nav) 就是这个新创建的引用的名字,value (在这个例子里就是 ‘#mainNav’) 是将被 ComponentQuery 用于查找组件。
我们创建了一个 addLogoutButton 函数,在这个函数里面通过调用getNav 函数调用了 ref。getNav这个getter函数从哪里来的?它是sencha touch 基本你定义的 refs 名称(也就是那个 key 值)自动生成的,并且保持同样的格式:以 get 开头,紧随大写字母开头的 refs 名称,这里就是 Nav 。在这个例子里面,我们看待 nav 是引用一条工具栏,我们在工具栏里面添加了一个Logout 按钮。 那么,这个 ref 将被认为是一个工具栏,请看以下代码:
- Ext.create('Ext.Toolbar', {
- id: 'mainNav',
- items: [
- {
- text: 'Some Button'
- }
- ]
- });
假设在我们运行 addLogoutButton 函数前这个工具栏就已经被创建,那么在运行 addLogoutButton 函数后,它将被多加一个 Logout 按钮。
高级Refs
Refs 可以设置更多的选项,不仅有名称和选择器。这些选择是 autoCreate 和 xtype,它们大多都是一起被用到的:
- Ext.define('MyApp.controller.Main', {
- extend: 'Ext.app.Controller',
- config: {
- refs: {
- nav: '#mainNav',
- infoPanel: {
- selector: 'tabpanel panel[name=fish] infopanel',
- xtype: 'infopanel',
- autoCreate: true
- }
- }
- }
- });
我们为Controller 添加了第二个 ref 。同样,名称就是 key,这里是 infoPanel, 但是,这次我们传入一个对象作为 value。 这次我们使用了一个更复杂的选择器进行查询。想象一下,你的 app 包含一个 tab panel ,并且其中一个子项(item) 名称是 fish。那么,上面设定的选择器就会在这个 ‘fish’ panel 的中匹配任何 xtype 为 infopanel 的子元素(items)。
这里不同的是,如果 infopanel 不存在于 'fish' panel 中,当在 Controller 中运行 this.getInfoPanel 的时候,它将会被自动创建。为什么它能够被自己创建? 因为我们为它指定了 xtype,在选择器没有查找到对象的时候,Controller 会自动为我们创建一个 infopanl 对象。
Control
与 refs 配置属性相关的就是 control. control 的意思就是让你的Controller 监听app里面的组件所触发的事件,并调用一些方法对这些事件进行响应。control的属性可配置成 ComponetQuery 选择器或者 refs 作为它的 keys,而事件处理函数名称字符串作为 values。请看以下例子:
- Ext.define('MyApp.controller.Main', {
- extend: 'Ext.app.Controller',
- config: {
- control: {
- loginButton: {
- tap: 'doLogin'
- },
- 'button[action=logout]': {
- tap: 'doLogout'
- }
- },
- refs: {
- loginButton: 'button[action=login]'
- }
- },
- doLogin: function() {
- // 当login button 被点击后调用
- },
- doLogout: function() {
- // 任何action=logout 的button被点击后调用
- }
- });
在上面的例子中,我们声明了两个 control :一个是 loginButton ref,另一个是任何action 值为 logout 的 button。每个一声明,我们都为其传入一个事件处理器: 每一个点击事件监听,我们都为其指定一个方法(处理器),当点击事件被触发时就会被调用到。请注意,我们这里指定的两个 'doLogin' 和 'doLogout' 方法都是以函数名称的字符串形式存在于 control 的代码块内。
Routes (路由,路径集)
在 Sencha touch 2 中,可以设定routes属性,让控制器引领至 app 的任何位置。
例如,假定我们有一个控制器负责响应登陆请求和查看用户配置信息请求,并想通过 urls 来访问这些页面。我们可以根据以下方式来实现:
- Ext.define('MyApp.controller.Users', {
- extend: 'Ext.app.Controller',
- config: {
- routes: {
- 'login': 'showLogin',
- 'user/:id': 'showUserById'
- },
- refs: {
- main: '#mainTabPanel'
- }
- },
- // 使用 'main' ref 来在主 TabPanel 上添加一个 loginpanel(注意, 'loginpanel' 是为这个 app 自定义的 xtype)
- showLogin: function() {
- this.getMain().add({
- xtype: 'loginpanel'
- });
- },
- // 加载用户信息并添加一个 'userprofile' view 到主 TabPanel
- showUserById: function(id) {
- MyApp.model.User.load(id, {
- scope: this,
- success: function(user) {
- this.getMain().add({
- xtype: 'userprofile',
- user: user
- });
- }
- });
- }
- });
上面例子中,routes 属性预先设定了浏览器地址和控制器功能的映射,当路径与某一个路径 (route) 匹配时,相应的功能将被调用。routes 可以是简单的文本内容,例如 route 'login' 匹配以下 url: http://myapp.com/#login 。或者可以包含通配符,正如 route 'user/:id’,匹配以下 url:http://myapp.com/#user/123. 即使路径改变,控制器仍会自动用指定的功能。