ExtJS 4 MVC多实例视图和子/子控制器的难点



我在ExtJS 4中遇到了MVC模式的问题。至少,我认为我有。我问了很多人这个问题,在Sencha论坛上发了很多次帖子,现在我转向更广泛的受众,希望得到一个灯泡或确认。

您的应用程序能够打开许多不同的视图,其中一些视图本身就是迷你应用程序。另外,用户可能希望打开一个视图的多个并发副本。

这个应用程序是一个单页面客户端Javascript应用程序。

ExtJS 4 MVC模型期望你在Application类中定义所有的控制器。然后在应用程序加载时初始化这些控制器。控制器跟踪视图、模型和存储。

当您多次初始化控制器A时,例如创建视图的多个副本,您最终会得到两个引用相同数据存储的视图,并在功能上将重复事件发送到应用程序事件总线。

我重构了我的应用程序,在组件和控制器中添加了新的原型方法,以允许a)子控制器(我的一些控制器变得非常大)和b)为它们所使用的视图定义专门的存储。模型仍然可以在控制器上定义,只是为了便于处理程序使用,如果你需要做一些事情,比如从服务器抓取一条记录。

我对MVC的理解会让我相信模型比控制器更直接地与视图相关。我假设ExtJS 4决定将存储(我认为可以看作是更经典模型的包装器)附加到控制器上,以鼓励重用加载的数据,并优化避免实例化相同类的许多副本。然而,在我看来,如果打算为用户提供许多视图实例,则无法做到这一点。在我看来,在OO框架中拥有许多实例是一个重要的选择,因此我为什么要逆潮流而行,在一些Ext基类上实现原型。

是否有办法有一个视图的多个并发实例与不同的数据加载到他们使用开箱即用的MVC类和使用提供的setter, getter等?

我也遇到了类似的问题:

考虑一个CRM类型应用程序的表面板,它为每个客户端打开一个视图的新实例。并且说选项卡视图包含3或4个行编辑网格面板,用于与与该客户端相关的不同数据集进行交互。

我想到的解决方案是基于Sencha论坛。简而言之,几乎所有从视图调度的事件都包含对视图本身的引用。控制器控制函数中的处理程序都使用这些来获取对正确视图实例的引用。

为了处理同一存储的多个实例,我从那篇文章中吸取了这一点:

对于视图上的Store实例或全局实例…这取决于的需求。如果你要使用全局,那就把它设为全局。如果你我们只需要它在视图上然后把它放在视图上。MVC是不是法律,你可以改变它来满足你的需要。技术上的MVC的控制器部分被认为是视图和模型部分,但有时根本不需要。我创建了95%的情况下,商店都在视图中。我给你举个例子…

如果你有一个商店的产品,你可能只需要引用在网格中存储。其他部分通常不需要应用程序。然而,如果你有一个Store来加载国家/地区,我通常需要全局的,所以我只需要加载它一次,然后可以在多个视图中设置/使用该Store

所以我只是创建了所需的存储,具体到一个视图实例,在视图的initComponent方法。应用程序确实有一些全局存储,我按照MVC建议将它们创建为存储类。它很好地封装了视图实例存储在视图内。然后我只需要一个控制器实例。

具体回答你的问题,目前,没有ExtJS官方建议或配置来处理使用相同存储构造函数的同一视图的多个实例。我花了一些时间寻找类似的东西,我找到的最好的是他们的一个论坛版主的推荐。

我不认为你需要超过1个控制器实例,不管你有多少视图/模型。查看这里的函数示例:

http://whatisextjs.com/extjs-4-extension/fieldset-w-dynamic-controls-7

这是可以做到的,相当容易。您需要遵循一些规则:

  1. 在应用启动时加载控制器。不要卸载它们。不要担心内存或时间,即使对于数百个控制器,它也相当小,只要你最小化并连接你的js.

  2. 永远不要使用控制器的refs或views属性。你将使用控制器的一个实例,但视图的多个实例,所以你永远不会想要一个对视图的引用。

  3. 只在控制器中使用事件监听器。你只会按照你的观点去听事件。你总是可以通过处理程序中的"cmp"参数在事件处理程序中获得对视图的(临时)引用。

  4. 要"启动"一个视图,创建它并将其添加到另一个视图。摧毁它,摧毁它。你不用控制器来启动视图。你可以使用控制器中的afterrender和beforedestroy事件来添加逻辑。

在ExtJS的MVC中,控制器是一个单例视图。我喜欢DeftJS对MVC的思考方式。视图的每个实例都有自己的控制器实例。通过这种方式,你可以将视图特定部分的所有"控制规则"放在控制器中,并且只有在视图打开时才会实例化。

我没有任何经验,我可以在同一个项目中使用多个Defts JS应用程序。

当然。是什么让你不这么认为的?下面是一个创建自定义视图的示例,该视图扩展自定义窗口组件。你可以在同一个控制器上多次运行这个方法,每次你都会得到一个View的新实例。

"this"指的是代码运行的控制器:

       this.getRequestModel().load(requestID,{       //load from server (async)
                 success: function(record, operation) {
                        var view = Ext.widget('requestEdit',{
                            title: 'MyRequest '+requestID
                        });
                        var form = view.down('form');
                        form.loadRecord(record);
                 }
         });

如何创建视图?我认为没有理由不能将不同的存储或配置数据传递给每个对象。一些代码示例将帮助您了解正在做的事情。例如,我们有一个类似的声音应用程序,一切都是通过扩展完成的。因此,如果我们需要一个网格,我们运行

Ext.define('MyApp.grids.something',{
extends:'Ext.grid.panel' 
//...

这些类是预定义的。然后,当控制器或视图加载这个网格时,它们使用

var grid=Ext.create('MyApp.grids.something',{id:'unique',store:mystore});

正如您所看到的,我们可以在每次创建网格时将不同的配置选项传递给相同的网格。我们可以像对待

一样对待它
Ext.create('Ext.grid.Panel');

当然,除了我们预先定义了一些选项,以及一些不可覆盖的选项,等等。

希望这有帮助。

查看这篇文章。这里的想法是从视图配置中获取一些配置(如storeitemId)并将其放入viewport配置:

// .../app/view/Viewport.js
Ext.define('MyApp.view.Viewport', {
    // ...
    items: [
        // ...
        { xtype: 'testview', store: 'Store1', itemId: 'instance1' },
        { xtype: 'testview', store: 'Store2', itemId: 'instance2' }
    ]
});

显然,存储的问题将得到解决。不同的itemId将使您能够正确处理事件

最新更新