代码之家  ›  专栏  ›  技术社区  ›  JulianR

javascript/extjs:“条件继承”?

  •  0
  • JulianR  · 技术社区  · 15 年前

    我们正在为一个Web应用程序使用extjs。在该应用中,我们使用标准 Ext.form.ComboBox 控制何时需要简单下拉列表,以及 Ext.us.Andrie.Select 控制何时需要下拉列表,您可以在其中选择多个值和/或清除该值。创建这两个类中的任何一个都需要一组用于配置选项的样板代码,所以我想要一个减少样板代码的类,当我在那里时,我希望这个类能够生成简单的下拉列表,或者更高级的下拉列表,这取决于配置选项。( multi: true clearable: true 但这比预期的要困难得多。

    这是我最接近的工作结果:

    MyComboBox = (function() {
    
        var singleDefaults = {
            typeAhead: false,
            triggerAction: 'all',
            selectOnFocus: false,
            allowBlank: true,
            editable: false,
            delay: 700
        };
    
        var multiDefaults = {
            typeAhead: false,
            triggerAction: 'all',
            selectOnFocus: false,
            allowBlank: true,
            editable: false,
            delay: 700
        };
    
        var constructor = function(config) {
    
                if (config.multi || config.clearable) {
                    config = Ext.apply(this, config, multiDefaults);
                    Ext.apply(this, Ext.ux.Andrie.Select.prototype);
                    Ext.apply(this, Ext.ux.Andrie.Select(config));
                    Ext.ux.Andrie.Select.prototype.constructor.call(this, config);
                } else {
                    config = Ext.apply(this, config, singleDefaults);
                    Ext.apply(this, Ext.form.ComboBox.prototype);
                    Ext.apply(this, Ext.form.ComboBox(config));
                    Ext.form.ComboBox.prototype.constructor.call(this, config);
                }
        };
    
        return function(config) {
            this.constructor = constructor;
            this.constructor(config);
        };
    
    })();
    

    嗯,没有 崩溃 但也不太管用。当设置成 Ext.ux.Andrie.Select ,它希望加载存储,即使加载了它,也不会展开下拉列表,除非您开始在字段中键入。

    另一个尝试的方法是:

    MyComboBox = Ext.extend(Ext.form.ComboBox, {
     constructor: function(config){
       if (config.multi || config.clearable) {
         Ext.form.ComboBox.prototype.constructor.call(this, config);
       } else {
         Ext.ux.Andrie.Select.prototype.constructor.call(this, config);
       }
     }
    });
    

    这不起作用,因为andrie下拉列表没有定义 constructor 它自己的函数,因此它最终调用 外部窗体组合框 ,它从中继承,这将导致一个正常的下拉列表,而不是多选择下拉列表。

    我认为这是特定于extjs的,但是如果您有一种框架不可知的方法来实现这一点,我可能可以将其转换为extjs。

    2 回复  |  直到 15 年前
        1
  •  3
  •   Justin Johnson    15 年前

    在构建中型到大型的JavaScript应用程序时,我发现将所有控件创建/实例化移动到单个类中很方便,因为每个方法都是该控件的工厂(即:组合框、文本区域、按钮、工具提示、复选框等)。因为只有工厂类才知道如何创建控件,这就增加了将视图逻辑与控件实例化本身分离的好处(当然,只要控件构造函数和接口保持不变)。

    WidgetFactory = {
        comboBox: function(config) {
            return config.multi || config.clearable
                ? this.comboBoxMultiple(config)
                : this.comboBoxSingle(config)
        },
    
        comboBoxSingle: function(config) {
            // ... boiler plate goes here ...
        },
    
        comboBoxMultiple: function(config) {
            // ... boiler plate goes here ...
        },
    
        textArea    : function(config) {},
        textBox     : function(config) {},
        checkbox    : function(config) {},
        radioButton : function(config) {},
        button      : function(config) {},
        slider      : function(config) {},
        colorPicker : function(config) {}
    
        // etc
    };
    

    将控件创建与视图分离允许您快速轻松地将控件实现换成另一个控件,而无需搜索整个应用程序来查找/替换该控件创建样板的所有实例。


    编辑:
    我无意暗示这将取代使用对象来创建/实例化控件,而是使用 除了 . 使用 WidgetFactory 作为所有控件的单一网关,它不仅能够更改超级类,还具有更大的灵活性。您可以交换整个类,而不必更改原始类,如果需要,可以使用多个不同的实现。

    例如,如果单个组合框是由某个类定义的, namespace.ui.combobox.single ,那么你可以

    comboBoxSingle: function(config) {
        return new namespace.ui.combobox.single(config);
    },
    

    但是,如果您需要突然使用一个不同的类来进行测试,那么您可以更改它。 一旦 在工厂里

    comboBoxSingle: function(config) {
        return new namespace.ui.combobox.single2(config);
    },
    

    并且可以轻松地来回切换,而无需更改实际的小部件类。

        2
  •  0
  •   JulianR    15 年前

    几乎忘了这个问题。我解决了这个问题,如果有人想知道,下面是如何做到的:

    var constructor = function(config) {
        if (config && (config.multi || config.clearable)) {
            config = Ext.apply(this, config, multiDefaults);
            Ext.applyIf(this, Ext.ux.Andrie.Select.prototype);
            Ext.ux.Andrie.Select.createDelegate(this)(config);
        } else {
            config = Ext.apply(this, config, singleDefaults);
            Ext.applyIf(this, Ext.form.ComboBox.prototype);
            Ext.form.ComboBox.createDelegate(this)(config);
        }
    };