原文:Using Both Shared and View-Specific Code in an Ext JS 6 Universal App
在本文,在展示如何编写Ext JS 6通用应用程序代码以使控制器和视图模型能适用于特定视图又是共享的。
想了解更多有关Ext JS 6的信息吗?请报名参加培训班吧。
本文的重点是通用应用程序,而不是只能用于纯classic或纯Modern的应用程序。特别是,app文件夹在通用应用程序中具有独特的用途。
背景
你可能已经听说过这个令人激动的消息,Ext JS已经将Sencha Touch组件合并到库里了。这将允许你使用传统的桌面Ext JS和移动Touch用户界面创建通用应用程序以运行在桌面、平板和智能手机上。
Sencha已经将这些组件家族放入名为“classic”和“modern”的两个工具包中。工具包classic中的是Ext JS组件集,而modern工具包中的是Sencha Touch 2组件集。每一个工具包的目标是去支持经典或现代的浏览器。Classic支持老旧的浏览器,如IE8,而modern则是针对现代浏览器,完全支持HTML5和CSS3。
通过设计,classic和modern工具包的目标是不同时代的浏览器。如果编写一个既保护classi和modern用户界面的应用程序,用户能看到到哪一个取决于运行环境。你不能混合或匹配视图组件。不过,这两个工具包都共享核心代码,如类系统、数据包以及视图-控制器-视图模型架构等等。
正因为如此,一个Ext JS 6通用应用程序可以将源代码划分为三个部分:classi、modern和共享。
如果使用Sencha Cmd 6来创建一个通用应用程序,会看到一个示例。打开终端窗口,兵导航到Ext JS 6文件夹并输入:
sencha generate app MyApp path/to/MyApp
起始应用程序会在app/store放至一个共享的store类Personnel.js,该类还有一个别名。无论是classic还剩modern的视图都可以请求改类并使用别名来创建他们自己的实例。在app/view/main目录下还有一个共享的控制器MainController.js,以及在app/view/main目录下会有一个共享的视图模型MainModel.js。这些类都可以被classsic或modern文件夹的主视图请求。
特定视图的控制器
如果打开MainController.js,会看到只有一个onItemSelected方法用来在用户选择一个条目时显示一个告警。当在grid中单击一个条目时,该方法既可以运行在classic视图,也可以运行在modern视图。
希望考虑过在classic视图与modern视图中做不同的实现?如在classic视图中使用Ext.Msg.alert(),而在modern视图中使用Ext.toast()。
这可通过创建从共享控制器扩展的特定视图的控制器来实现。
要实现这个,需要在app文件夹将共享的控制器改名为MainControllerShared。然后创建两个新的控制器,一个位于classic,而另一个位于modern。这两个都要扩展自共享的控制器。
这样,classic的主视图将请求在classic中的控制器,而modern视图则请求在modern中的控制器。这些控制器中的每一个都有一个别名,且都扩展自共享控制器。然后,移除共享控制器中的方法和别名并实现特定视图的版本。
由于名称MyApp.view.main.MainController是相同的,但他们的位置在文件系统中已经从app文件夹修改为classic和modern文件夹,使用sencha app refresh来处理并让微加载来指定加载哪个是相当棒的想法。
这些控制器的最终代码类似如下代码:
//app/view/main/MainControllerShared.js:
Ext.define('MyApp.view.main.MainControllerShared', {
extend: ‘Ext.app.ViewController'
});
//classic/src/view/main/MainControllerShared.js:
Ext.define('MyApp.view.main.MainController', {
extend: 'MyApp.view.main.MainControllerShared',
alias: 'controller.main',
onItemSelected: function(sender, record) {
Ext.Msg.alert('Star Trek', record.data.name);
}
});
//modern/src/view/main/MainControllerShared.js:
Ext.define('MyApp.view.main.MainController', {
extend: 'MyApp.view.main.MainControllerShared',
alias: 'controller.main',
onItemSelected: function(sender, record) {
Ext.toast(record.data.name);
}
});
在这里不在有共享的控制器逻辑,不过有机会还是可以将共享的事件处理程序放回共享的控制器,又或者可以实现一个initViewModel方法把需要的任何逻辑放在哪里。如果子类控制器需要initViewModel方法,要确保这些方法的第一句是“this.callParent(arguments); ”来确保祖先的方法被执行。
特定视图的视图模型
现在,已经知道了如何去实现既共享又用于特定视图的控制器,哪如何去实现类似的视图模型呢?
首先,看看共享的视图模型,它包含了两个数据属性:name和loremlpsum。这些都会在两个视图中使用。
下面替换classic视图用户标签页中gird的store,让它只使用于classic视图,这意味着需要一个专属于classic视图的store。
首先,将classic/src/view/main/Main.js中的第二个标签修改为以下代码:
{
iconCls: 'fa-user',
xtype: 'grid',
title: 'Beatles',
columns: [{
text: 'Name',
dataIndex: 'first',
flex: 1
}],
bind: {
store: '{beatles}'
}
}
代码将创建一个绑定视图模型中名为“{beatles}”的store的grid,该store尚不存在。
限制,重命名共享的视图模型类并创建特定视图的视图模型类,正如刚才控制器中所做的那样。在共享的视图模型中留下数据属性(包括name和loremlpsum),因为classic或modern的视图任然会使用这些属性。
由于beatles的store只使用在classic视图,而modern视图起始并不需要视图模型,但我们做事要有始有终。
与之前一样,由于一些类移动了位置,因而执行sencha app refresh是一个好主意。
现在,在classic的视图模型添加store:
Ext.define('MyApp.view.main.MainModel', {
extend: 'MyApp.view.main.MainModelShared',
alias: 'viewmodel.main',
stores: {
beatles: {
autoLoad: true,
data: [
{first: 'John'},
{first: 'Paul'},
{first: 'George'},
{first: 'Ringo'}
],
proxy: {type: 'memory'}
}
}
});
如果现在运行应用程序,就会看到classic视图已经在使用beatles store了。该store只会在classic视图中使用,而classic或modern视图仍然在使用共享的视图模型属性name和loremlpsum。
小结
使用神奇的Sencha类系统,可取轻易的编写视图以及既共享又适用于特定视图的控制器和视图模型。
作者:Max Rahder
Max is a member of the Sencha Training team, with over 25 years of experience in web and mobile app development, HTML5, JavaScript, Java and cloud computing. He has given scores of training classes across the US and Europe.