6

考虑一个具有自定义过滤逻辑和不同加载模式的复杂应用程序;隐藏时延迟加载,隐藏时不加载,但在显示时加载并在修改自定义过滤器时重新加载等。

mvc 应用程序的哪一部分应该负责加载,以及如何将它们全部连接起来?

4

2 回答 2

15

当我开始使用 MVC 时,我从未从 Sencha 那里找到明确的答案,但我可以告诉你我为一些应用程序成功做了什么。

我根据它们的使用方式创建和加载我的商店。对我来说,这似乎分为三个不同的类别:

  1. 适用于整个应用的商店

  2. 适用于所有视图实例的存储

  3. 绑定到单个视图实例的商店

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. 适用于所有视图实例的存储

我像第一个类别一样创建和加载这些,只是我将它们放在特定视图控制器的stores数组中,而不是“主”控制器stores数组中。

然后这是相同的基本概念,autoLoad: true如果它们依赖于另一家商店的数据,则有些不是。

对于那些不是autoLoad: true它们的人,它们会被加载到控制器init函数内部的某个地方,或者是某些事件被触发的结果。

3. 绑定到单个视图实例的商店

在这里,我可能会反对 MVC 粒度,但是对于应用到单个视图实例的存储来说,确实没有比在视图本身内部更好的地方了。

在大多数情况下,我什至没有将这些商店放在视图控制器的stores数组中。initComponent我只是在视图的函数中创建并加载它们。因此,当视图被销毁时,不再有对 store 的引用,因此 store 也将被销毁。这有助于减少可以多次创建的商店的资源。

例如,假设您有一个MyApp.view.UnicornWeightGrid扩展 agridpanel并显示独角兽随时间逐渐增加的权重的 a。用户可以UnicornWeightGrid为领域中的所有独角兽打开一个用于比较和交叉引用的目的。的不同实例与 的实例一样UnicornWeightStoreUnicornWeightGrid

视图可以这样定义:

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”是一种非常松散的设计模式,它在我使用过的几乎每一个框架中都有不同的定义和实现。所以你几乎可以做任何最适合你的事情。

于 2012-08-24T16:50:42.067 回答
0

您应该将逻辑加载到将显示此商店的网格控制器中的商店。我把它们放在afterrender事件的处理程序中。

于 2012-08-24T16:18:23.737 回答