【发布时间】:2012-08-19 19:41:28
【问题描述】:
考虑一个具有自定义过滤逻辑和不同加载模式的复杂应用程序;隐藏时延迟加载,隐藏时不加载,但在显示时加载并在修改自定义过滤器时重新加载等。
mvc 应用程序的哪一部分应该负责加载,以及如何将它们全部连接起来?
【问题讨论】:
标签: javascript model-view-controller extjs4 extjs-mvc
考虑一个具有自定义过滤逻辑和不同加载模式的复杂应用程序;隐藏时延迟加载,隐藏时不加载,但在显示时加载并在修改自定义过滤器时重新加载等。
mvc 应用程序的哪一部分应该负责加载,以及如何将它们全部连接起来?
【问题讨论】:
标签: javascript model-view-controller extjs4 extjs-mvc
当我开始使用 MVC 时,我从未从 Sencha 那里找到明确的答案,但我可以告诉你我已经成功地为一些应用程序做了什么。
我根据商店的使用方式创建和加载商店。对我来说,这似乎分为三个不同的类别:
适用于整个应用的商店
适用于所有视图实例的存储
绑定到单个视图的商店实例
1.适用于整个应用的商店
我通常有一个“主”控制器来处理我的应用程序的框架,比如键盘导航、主菜单等。
属于上述第一类的存储进入此“主”控制器的stores 数组。如果这些商店不依赖于另一家商店,那么我只需将它们设为autoLoad: true 并完成它们。但是在它们依赖于另一个存储数据的情况下,我会向父存储添加一个侦听器,以在父的 onLoad 事件中加载依赖存储。
我发现属于第一类的一些商店的一个例子是我在整个应用程序的组合框中使用的参考商店,通常在许多不同类型的视图中。这些通常配置为autoLoad: true,然后我再也不会为该用户的会话加载它们。每当我需要一个使用参考存储的组合框时,我都可以这样设置:
{
xtype: 'combobox',
allowBlank: false,
forceSelection: true,
store: Ext.getStore('SomeReferenceStore'),
queryMode: 'local', // this makes sure the store doesn't reload
valueField: 'id',
displayField: 'name'
}
举两个商店的例子,它们都属于第一类,其中一个依赖于另一个:
在我的一个应用程序中,我拥有动态数量的用户权限,当用户登录应用程序时,我需要获取不同的权限并修改 User 模型以包含每个不同权限的布尔字段:
Ext.define('MyApp.controller.Main', {
extend: 'Ext.app.Controller',
models: [
'User',
'Reference',
// etc...
],
stores: [
'CurrentUser',
'PermissionRef', // this is "autoLoad: true"
// etc...
],
init: function() {
var me = this;
// update the user model and load the user
me.getPermissionRefStore().on('load', function(store, records) {
var model = me.getUserModel(),
fields = model.prototype.fields.getRange();
// append the permissions onto the User model fields
Ext.each(records, function(permission) {
fields.push({
name: permission.get('name'),
type: 'bool',
});
});
// update the user model with the permission fields
model.setFields(fields);
// load the current user
me.getCurrentUserStore().load();
// other stuff...
});
// other stuff...
}
});
有了这个,每当我需要对用户的引用以及他有哪些可用权限时,我只需调用:
var user = Ext.getStore('CurrentUser').first();
有时视图也将依赖于正在加载的商店。例如,我的主菜单项由数据库表确定,在这种情况下,我将以相同的方式包含一个 onLoad 侦听器(在控制器的 init 函数内):
// create the menu once we know what menu items are available
me.getMenuStore().on('load', function(store) {
me.getViewport().add(Ext.widget('mainpanel'));
});
MyApp.store.Menu 本身将配置为autoLoad: true。
2。适用于所有视图实例的存储
我像第一个类别一样创建和加载这些,只是我将它们放在特定 view 控制器的 stores 数组中,而不是“主”控制器 stores 数组中。
那么基本概念是一样的,有些是autoLoad: true,有些不是,如果它们依赖于其他商店的数据。
对于不是autoLoad: true 的那些,它们会被加载到控制器的init 函数内的某个地方,或者是由于某些事件被触发。
3.绑定到单个视图的商店实例
在这里,我可能会违反 MVC 粒度,但是对于应用到单个视图实例的存储,然后在视图本身内部,确实没有比这更好的地方了。
在大多数情况下,我什至不将这些存储放在视图控制器的 stores 数组中。我只是在视图的initComponent 函数中创建并加载它们。因此,当视图被销毁时,不再有对 store 的引用,因此 store 也将被销毁。这有助于减少可以多次创建的商店的资源。
例如,假设您有一个 MyApp.view.UnicornWeightGrid,它扩展了一个 gridpanel,并显示独角兽随着时间的推移而逐渐增加的重量。用户可以为领域中的所有独角兽打开UnicornWeightGrid,以进行比较和交叉引用。 UnicornWeightStore 的不同实例与UnicornWeightGrid 的实例一样多。
视图可以这样定义:
Ext.define('MyApp.view.UnicornWeightGrid', {
extend: 'Ext.grid.Panel',
alias: 'widget.unicornweight',
requires: [
'MyApp.model.UnicornWeight'
],
closable: true,
initComponent: function() {
var me = this;
me.store = Ext.create('Ext.data.Store', {
model: 'MyApp.model.UnicornWeight',
proxy: {
type: 'ajax',
url: 'unicorns/weight',
extraParams: {
name: me.unicornName
}
}
});
me.store.load();
});
});
然后,每当我们想要获得不同的UnicornWeightGrid 时,我们可以简单地调用:
var grid = Ext.widget('unicornweight', {
unicornName: someUnicornNameVariable
});
myTabPanel.add(grid);
我需要在视图中定义的商店上的任何onLoad 侦听器,我也在视图中附加。所以我真的不需要其他任何地方的参考。
话虽如此,这绝不是设置商店的唯一方法。
我发现这是在创建几个不同的 ExtJS“MVC”应用程序时始终如一地处理商店的最可行的方法,但在“特殊”情况下我有时也会采用不同的方式。
您应该记住,“MVC”是一种非常松散的设计模式,它在我使用过的几乎每个单独的框架中都有不同的定义和实现。所以你几乎可以做任何最适合你的事情。
【讨论】:
您应该将逻辑加载到将显示此商店的网格控制器中的商店。我把它们放在afterrender事件的处理程序中。
【讨论】: