sencha touch 有一套自己的类机制,可以以面向对象的方式去写代码,封装业务逻辑,sencha touch 的组件、插件、api等都建立在这一套类机制的上面
在实际开发中,我们需要遵循这一套机制,以免造成不必要的麻烦。
所以的类都是继承于Ext.Base
定义一个类的语法:Ext.define(className, properties);
其中className是类名,properties属于配置。
sencha touch开发推荐使用mvc结构,在这里我推荐以下结构
如图所示,我们一般在app文件夹中进行开发,其中config属于全局配置文件,是一个静态类
代码如下:
1 //全局配置文件 2 Ext.define('app.config', { 3 //设置别名是为了方便调用,这样直接config.name就能获取到变量。 4 alternateClassName: 'config', 5 statics: { 6 version: '1.0.0', 7 used: { 8 add: 'http://www.361y.cn:8080/Json/Used.asmx/Add', 9 update: 'http://www.361y.cn:8080/Json/Used.asmx/Update', 10 destroy: 'http://www.361y.cn:8080/Json/Used.asmx/Delete', 11 list: 'http://www.361y.cn:8080/Json/Used.asmx/List', 12 one: 'http://www.361y.cn:8080/Json/Used.asmx/One' 13 } 14 } 15 });
如上所示,className的命名属于命名空间,此静态类的className是app.config,在这里表示app文件夹中的config.js文件。
为了方便调用,我们为他配置了alternateClassName属性。
我们在statics属性中配置全局变量,此类中我们只是配置了变量。
我们还可以在里面配置方法,不过为了方便维护,在另一个静态类中进行配置。
代码如下:
1 //公用类 2 Ext.define('app.util', { 3 alternateClassName: 'util', 4 statics: { 5 //比较两个对象是否相等 6 equals: function (x, y) { 7 if (x === y) { 8 return true; 9 } 10 if (!(x instanceof Object) || !(y instanceof Object)) { 11 return false; 12 } 13 if (x.constructor !== y.constructor) { 14 return false; 15 } 16 for (var p in x) { 17 if (x.hasOwnProperty(p)) { 18 if (!y.hasOwnProperty(p)) { 19 return false; 20 } 21 if (x[p] === y[p]) { 22 continue; 23 } 24 if (typeof (x[p]) !== "object") { 25 return false; 26 } 27 if (!Object.equals(x[p], y[p])) { 28 return false; 29 } 30 } 31 } 32 for (p in y) { 33 if (y.hasOwnProperty(p) && !x.hasOwnProperty(p)) { 34 return false; 35 } 36 } 37 return true; 38 }, 39 //重写ajax(需要初始化) 40 overrideAjax: function () { 41 var me = this; 42 //开始加载 43 Ext.Ajax.on('beforerequest', 44 function (connection, options) { 45 if (!options.hidMessage) { 46 me.showMessage('正在努力加载中...'); 47 } 48 }); 49 //加载成功 50 Ext.Ajax.on('requestcomplete', 51 function (connection, options) { 52 me.hideMessage(); 53 }); 54 //加载失败 55 Ext.Ajax.on('requestexception', 56 function (connection, options) { 57 if (!options.hidMessage) { 58 me.showMessage('加载失败,请检查网络是否正常...', true); 59 } 60 }); 61 }, 62 //重写list(需要初始化) 63 overrideList: function () { 64 //重写分页插件 65 Ext.define("Ext.zh.plugin.ListPaging", { 66 override: "Ext.plugin.ListPaging", 67 config: { 68 //自动加载 69 autoPaging: true, 70 //滚动到最底部时是否自动加载下一页数据 71 noMoreRecordsText: '没有更多内容了', 72 loadMoreText: '加载更多...' //加载更多按钮显示内容 73 } 74 }); 75 //重写下拉刷新 76 Ext.define("Ext.zh.plugin.PullRefresh", { 77 override: "Ext.plugin.PullRefresh", 78 config: { 79 lastUpdatedText: '上次刷新时间:', 80 loadedText: '等一会再刷新吧...', 81 loadingText: '加载中...', 82 pullText: '下拉可以手动刷新', 83 releaseText: '松开可以刷新', 84 lastUpdatedDateFormat: 'Y-m-d H:i' 85 } 86 }); 87 //重写List 88 Ext.define("Ext.zh.List", { 89 override: "Ext.List", 90 config: { 91 //取消选择效果 92 selectedCls: '', 93 //禁用加载遮罩,防止跳转时页面卡顿,使用统一的遮罩效果 94 loadingText: false, 95 cls: 'list', 96 deferEmptyText: false, 97 emptyText: '没有更多内容了' 98 } 99 }); 100 }, 101 //重写Pick相关(需要初始化) 102 overridePick: function () { 103 Ext.Date.monthNames = ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"]; 104 Ext.define("Ext.zh.DatePicker", { 105 override: "Ext.picker.Date", 106 config: { 107 yearFrom: 2000, 108 monthText: '月', 109 dayText: '日', 110 yearText: '年' 111 } 112 }); 113 Ext.define("Ext.local_zh_cn.Picker", { 114 override: "Ext.picker.Picker", 115 applyDoneButton: function (config) { 116 if (config) { 117 if (Ext.isBoolean(config)) { 118 config = {}; 119 } 120 if (typeof config == "string") { 121 config = { 122 text: config 123 }; 124 } 125 Ext.applyIf(config, { 126 ui: 'action', 127 align: 'right', 128 text: '确定' 129 }); 130 } 131 return Ext.factory(config, 'Ext.Button', this.getDoneButton()); 132 }, 133 applyCancelButton: function (config) { 134 if (config) { 135 if (Ext.isBoolean(config)) { 136 config = {}; 137 } 138 if (typeof config == "string") { 139 config = { 140 text: config 141 }; 142 } 143 Ext.applyIf(config, { 144 align: 'left', 145 text: '取消' 146 }); 147 } 148 return Ext.factory(config, 'Ext.Button', this.getCancelButton()); 149 } 150 151 }); 152 }, 153 //app初始化执行 154 inIt: function () { 155 this.overrideList(); 156 this.overrideAjax(); 157 this.addMessage(); 158 this.overridePick(); 159 } 160 } 161 });
如此我们可以通过util.equals('a','b')调用指定方法,另外我们可以通过this来进行内部调用
以上两个类不会自动创建,我们必须创建之后才能调用。一般我们在app.js中进行创建
代码如下:
1 Ext.application({ 2 name: 'app', 3 requires: ['app.config','app.util', 'Ext.MessageBox'], 4 controllers: ['Main', 'Used', 'User', 'Job'], 5 launch: function () { 6 // Destroy the #appLoadingIndicator element 7 Ext.fly('appLoadingIndicator').destroy(); 8 util.inIt(); 9 // Initialize the main view 10 Ext.Viewport.add(Ext.create('app.view.Main')); 11 } 12 });
在此代码中我们通过requires进行了创建。
值得注意的是,全局变量,公共方法不止以上一种写法,你可以自行尝试一下其他写法。
下面来说一说普通类,例如一个视图。
代码如下:
1 Ext.define('app.view.About', { 2 alternateClassName: 'about', 3 extend: 'Ext.Container', 4 xtype: 'about', 5 requires: ['ux.plugin.ConHref'], 6 config: { 7 title: '关于我们', 8 margin: 10, 9 plugins: 'conHref', 10 html: '<p>“抛砖网”国内首家首创纯实战型培训机构,提供在线培训、技术指导及答疑!</p><br/><p>团队通过360全方位技术培训+1度手把手技术指导,保证每一个学员能最快掌握实际工作技能;</p><br/><p>让每一个学员都能站在我们的肩膀上,展翅高飞。赶快关注“抛砖网”。</p><br/><p>网址:<a href="http://www.361y.cn">www.361y.cn</a></p><p>QQ群:263271569</p><p>官方微信号:paozhuanedu</p><br/><p><strong>本期课程说明及付费链接:</strong></p><p><a href="http://item.taobao.com/item.htm?id=36768998716">item.taobao.com/item.htm?id=36768998716</a></p>' 11 } 12 });
这是一个视图类,所在路径为app/view/About.js
在这里设置alternateClassName是为了方便创建,我们可以通过Ext.create('about')来创建类,等同于
Ext.create('app.view.About')
extend属性表示他继承于Ext.Container这个类。
xtype是为了方便在控制层中进行监听,通常此属性是必须的。
requires表示这个类所依赖的类,在这里是指一个插件。通过config.plugins来使用
config表示此类中的各种配置,框架自动帮每一个配置项添加了以下方法:
getter方法 - 如getName就是返回name的当前值。
setter方法 - 如getName就是为name设置一个新值。
getter和setter都是自动生成的,建议大家使用它们来存取类里面的数据。ST的每一个组件都使用了getter和setter的模式,这意味着如果我们知道一个配置项,也就知道如何获取和设置它的值了。
这也让你的的代码更整洁。
如果你需要在视图创建时就添加一个按钮,并且能够动态更新。
可以如下:
1 /** 2 * 基于Ext.navigation.Bar 3 * 去除动画切换等功能 4 * 可以灵活的在NavigationView子项中配置属性 5 * 小写开头表示这是私有控件,不能直接使用 6 */ 7 Ext.define('ux.navigationBar', { 8 extend: 'Ext.TitleBar', 9 requires: [ 10 'Ext.Button', 11 'Ext.Spacer' 12 ], 13 config: { 14 /*导航栏标题*/ 15 title: null, 16 /*item默认类型*/ 17 defaultType: 'button', 18 layout: { 19 type: 'hbox' 20 }, 21 /*返回按钮*/ 22 backButton: { 23 align: 'left', 24 ui: 'back', 25 hidden: true 26 } 27 }, 28 /*初始化配置*/ 29 constructor: function (config) { 30 config = config || {}; 31 if (!config.items) { 32 config.items = []; 33 } 34 this.callParent([config]); 35 }, 36 /*创建返回按钮*/ 37 applyBackButton: function (config) { 38 return Ext.factory(config, Ext.Button, this.getBackButton()); 39 }, 40 /*更新返回按钮*/ 41 updateBackButton: function (newBackButton, oldBackButton) { 42 if (oldBackButton) { 43 this.remove(oldBackButton); 44 } 45 if (newBackButton) { 46 this.add(newBackButton); 47 48 newBackButton.on({ 49 scope: this, 50 tap: this.onBackButtonTap 51 }); 52 } 53 }, 54 /*点击返回按钮时触发*/ 55 onBackButtonTap: function () { 56 this.fireEvent('back', this); 57 } 58 });
如上,applyBackButton方法在视图创建时会自动调用,只有返回的值部位false,并且不等于旧的值,就会自动触发updateBackButton方法,我们可以在里面进行逻辑处理。
另外一个类还值得主要的属性有:
alias :类似于alternateClassName,但是它的值只能是string数组
inheritableStatics:可继承的静态方法列表
mixins :额外需要继承的类
platformConfig:特殊平台或者主题中的默认配置
singleton:是否单例模式
uses :不一定依赖的类