model-view-controller - 一个 Extjs 应用程序调用另一个 Extjs 应用程序

标签 model-view-controller extjs extjs4.1 sencha-command

使用 Sencha Cmd 生成工作区并创建两个不同的应用程序后,我只想运行第一个应用程序,然后单击按钮后,它会调用第二个应用程序 :)
像一个主应用调用另一个子应用
有办法吗?
谢谢你的帮助

最佳答案

您可以开发可以毫无问题地协同工作的独立模块。这两个概念根本没有冲突。

在这里分享一下我的经验。当我们开始我们当前的项目时(从头开始),另外两个团队正在开发另外两个应用程序,一段时间后我们应该将它们“集成”到一个大应用程序中。您不必是天才就能预测最终结果,对吧?当我们听说客户想要更多并行工作(更多团队开发模块)时,情况变得更糟。

第一个想法是使用 iframe,但 PoC 证明这是一个坏主意,所以我们停止了机器并开始设计可插拔架构。我们做得很好,因为目前我们能够轻松加载以隔离方式开发的模块(我们称之为插件)。例如,看看我们的文件夹结构是怎样的:

enter image description here

这是我们设置要加载的模块的元数据:
enter image description here

这有很多优点:

  • 模块可以并行开发,
  • 模块可以隔离测试,
  • 模块可以动态加载、启用或禁用

  • 当然,这不是 extjs 开箱即用的东西,但你可以这样做,因为它值得。

    所以,简短的回答:你的问题不是应用程序的大小,而是它的结构。像我们一样遵循推荐的具有自定义文件夹结构的 MVC 模式。

    更新:

    关于插件元数据。应用程序主 Controller 只有一个职责:加载插件。这是通过以下代码完成的:
    discoverPlugins: function () {
        var me = this;
        Ext.each(plugins(), function (d) {
            me.loadPluginController(d.controller);
        });
    
        App.History.notifyAppLoaded();
    },
    
    loadPluginController: function (controllerName) {
        try {
            var controller = App.current.getController(controllerName);
            controller.init(App.current);
        } catch (e) {
            console.log(controllerName + ' controller couldn\'t be loaded.' + e);
        }
    },
    

    每个插件 Controller 都充当调度程序,也就是说,有一个历史组件监听 url(在地址栏中),当它发生变化时,逐个插件迭代插件,请求处理 url。当插件能够处理请求的 url 时,该过程结束。
    这是“操作”插件的调度程序配置:
    constructor: function () {
        this.callParent(arguments);
        this.router.set({
            '!/operations/product/permissions/definition': this.viewPermissionsDefinition,
            '!/operations/product/accesslist/create': this.createProductAccessList,
            '!/operations/product/accesslist/{id}/edit': this.editProductAccessList,
            '!/operations/product/accesslist/{id}': this.viewProductAccessList,
            '!/operations/product/accesslist': this.viewProductAccessList,
            '!/operations/{...}': this.notFound,
            '!/operations': this.root
        });
    } 
    

    这是历史类代码的导航方法:
    navigate: function (token) {
        var me = this,
            handled;
    
        if (token) {
            handled = false;
            for (var i = 0; i < me.routers.length; i++) {
                if (me.routers[i].processToken(token)) {
                    handled = true;
                    break;
                }
            }
    
            if (!handled) {
                App.current.fail(404, 'Resource not found.');
            }
        } else {
            App.current.gotoUrl('/servicedesk/search');
        }
    },
    

    重要的一点是插件只引用一个共享组件:渲染它们的中心区域:
    refs: [
        { ref: 'main', selector: '#center-panel' }
    ],
    

    此引用由所有插件 Controller 继承,这些插件 Controller 是“AbstractPluginController”的子类。这很重要,因为模块只知道它们的宿主。这就是我们可以并行发展的原因。

    关于 AbstractPluginController,这个类有一些对所有插件 Controller 有用的核心功能,例如,为了在需要时而不是在此之前加载他们所有的 Controller / View /模型,这个类实现了如下动态 Controller 加载:
    createControllerGetters: function (controllers) {
        var me = this;
        controllers = Ext.Array.from(controllers);
        Ext.Array.each(controllers, function (controllerName) {
            var parts = controllerName.split('.'),
                idx = parts.indexOf('controller'),
                significants = parts.slice(idx + 1),
                name = significants.map(function (e) { return Ext.String.capitalize(e); }).join(''),
                fn = 'get' + name + 'Controller';
    
            if (!me[fn]) {
                me[fn] = Ext.Function.pass(me.getController, [controllerName], me);
            }
        });
    },
    
    getController: function (controllerName) {
        this.controllerCache = this.controllerCache || {};
        var me = this,
            cached = me.controllerCache[controllerName];
    
        if (!cached) {
            me.controllerCache[controllerName] = cached = App.current.getController(controllerName);
            if (cached) {
                cached.init();
                cached.on('beforedestroy', function () {
                    me.controllerCache[ref] = null;
                });
            }
        }
    
        return cached;
    },
    

    这允许我们指定模块具有的子 Controller 列表(因为主 Controller 只是一个初始化器和调度),并允许我们按需创建它们。
    controllers: [
        'Operations.controller.ProductAccessListViewer',
        'Operations.controller.ProductAccessListEditor',
        'Operations.controller.ProductAccessListCreator'
    ],
    

    总结:我认为主要有以下几点:
  • 模块不必了解主机应用程序的任何信息。
  • 通过链接进行导航/通信,主要是
  • 主机使用元数据执行的集成(插件也可以公开额外的元数据)
  • Controller 的延迟加载(他们用自己的 View 做某事)

  • 我希望这能给你一个想法。有很多细节和一些整合它们的技巧,但基本上,我想在这里展示的是一个模块化应用程序可以(或应该)用 extjs 开发,只需一点额外的努力。

    关于model-view-controller - 一个 Extjs 应用程序调用另一个 Extjs 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13939305/

    相关文章:

    extjs - 你如何获得所有商店参数? (ExtJS 4.1)

    javascript - 如何防止 ExtJs 菜单容器溢出主体?

    iOS:在不同 View 上使用 NSUserDefault 数据更新文本标签

    ruby-on-rails - 为什么重定向错误?

    javascript - Node 中的 MVC 和一般 : How are models tied to views?

    javascript - 如何使用入门套件中的自定义应用程序添加 Rally 卡渲染器?

    c++ - 使用 QStyledItemDelegate::paint() 直接在 QListView 上绘制小部件

    ExtJS 4.1 如何动态创建带网格的窗口

    javascript - XMLHttpRequest 响应在 Internet Explorer 中没有 header

    extjs 4.1 如何在xtemplate中显示编号和项目符号