在ExtJS中覆盖类/属性的最佳实践是什么?

33

我有一个Ext.form.field.Text,想要覆盖setValue函数。

在ExtJS中,推荐的方式是什么来覆盖这个类的功能?Ext.override吗?


6
我已经编辑了这个问题,使其更有建设性。请重新打开这个问题,因为答案对于ExtJs社区非常有用。 - A1rPun
3个回答

79

为了澄清:我所谓的真实的类修改是指有意图的对一个类进行永久性修改/扩展,这应该总是通过扩展一个类来完成。但它不是针对特定问题(修复漏洞等)的临时解决方案

您至少有四种覆盖(Ext)Classes成员的选项

  • 原型 我想是众所周知的,它允许您为类的所有实例覆盖成员。您可以像这样使用它

    Ext.view.View.prototype.emptyText = "";
    

    虽然你不能像这样使用它

    // callParent is NOT allowed for prototype
    Ext.form.field.Text.prototype.setValue = function(val) {
        var me = this,
            inputEl = me.inputEl;
    
        if (inputEl && me.emptyText && !Ext.isEmpty(value)) {
            inputEl.removeCls(me.emptyCls);
            me.valueContainsPlaceholder = false;
        }
    
        me.callParent(arguments);
    
        me.applyEmptyText();
        return me;
    };
    

    这里有一个JSFiddle

    这种方式不应该用于真正的类修改。

  • Ext.override 几乎与原型链的作用相同,但它完全适用于 ExtJS 类系统,使您可以使用 callParent()

    您可以像这样使用它

    // callParent is allowed for override
    Ext.override('Ext.form.field.Text', {
        setValue: function(val) {
            this.callParent(['In override']);
            return this;
        }
    });
    

    这里有一个JSFiddle(修复了c-p错误!感谢@nogridbag

    使用场景:我遇到了一个(我认为仍存在的)radiogroup的不良行为,其中ExtJS期望一个对象(键值对)以正确设置值。但我的后端只返回一个整数。我首先使用Ext.overridesetValue()方法应用了一个修复程序,然后从radiogroup中扩展。在那里,我只是从给定的值创建一个键值对,并使用它调用父方法。

    @rixo所提到的,这可以用于覆盖实例成员。因此,即使是mixins(我自己从未测试过),也可能有资格进行覆盖。

    var panel = new Ext.Panel({ ... });
    Ext.override(panel, {
        initComponent: function () {
            // extra processing...
    
            this.callParent();
        }
    });
    

    这种变体不应该用于真正的类修改。

  • 继承一个现有的类以应用额外的行为和渲染。使用此变体创建一个子类型,使其具有不同的行为,同时又不失原始类型。

    在以下示例中,我们通过添加一个名为setColored的方法来扩展文本字段,并覆盖setValue方法来处理直接调用setValue时移除标签颜色的情况。

  • Ext.define('Ext.ux.field.Text',{
        extend: 'Ext.form.field.Text',
        widget: 'uxtextfield',
        setColored: function(val,color) {
            var me = this;
            if (me.settedCls) {
                me.removeCls(me.settedCls);
            }
            me.addCls(color);
            me.settedCls = color;
            me.setValue(val,true);
        },
        setValue: function(val,take) {
            var me = this;
            if (!take && me.settedCls) {
                me.removeCls(me.settedCls);
            }
            me.callParent(arguments);
            return me;
        }
    });
    

    这是一个JSFiddle

    只覆盖实例在极少数情况下会发生,并且可能不适用于所有属性。在这种情况下(我手头没有示例),您只需对不同行为进行单个操作,就可以考虑仅针对实例覆盖设置。基本上,当您在类创建时应用配置时,您总是这样做,但大多数时间您只覆盖配置属性的默认值,但您也可以覆盖引用函数的属性。这将完全覆盖实现,您可能无法访问基础类型(如果存在),这意味着您无法使用callParent。您可以尝试使用setValue来查看它是否不能应用于现有链。但是,再次强调,您可能遇到一些罕见的情况,在开发时即使仅重新实现也很有用。对于这种情况,您应该在创建特定对象后使用Ext.override进行覆盖。

    重要提示:如果您不使用Ext.override,则无法通过调用this访问类实例!

    如果我遗漏了什么或某些内容不准确,请评论或随意编辑。

    正如@Eric评论的那样:

    这些方法都不允许您覆盖混入项(如Ext.form.field.Field)。由于混合函数在定义类时复制到类中,因此必须直接将覆盖应用于目标类。


5
回答很好,但是我想提一点小细节。这些方法都不能让你覆盖掉混入的方法(例如Ext.form.field.Field)。因为混入函数在定义类时被复制到类中,所以你必须直接将覆盖应用于目标类。 - Eric
是否有一种方法可以覆盖一个类,只有在该方法不存在的情况下才使用新方法?我想确保在将来升级到可能实现此功能的 ExtJS 的较新版本时,我们不会丢失功能。 - AsGoodAsItGets
1
@AsGoodAsItGets 我认为你在谈论的是其他语言中的一些操作,需要使用像 override 这样的关键字,否则会出现错误。ExtJS 不支持这个功能。但是你可以添加一个自定义的 Ext.override 来实现,只有在方法不存在时才适用。我只是不会把它命名为 override ;) 另一种方法是在 initComponent 中的 callParent 调用后进行检查,如果方法不存在,则应用它。你可以使用 Ext.applyIf 来实现。但你永远不会知道同名函数是否真的做了相同的事情! - sra
@sra 是的,这基本上就是我想做的事情,相当于 PHP 的 method_exists 函数。当然你永远不会知道这个函数是否完全相同,但在我的情况下(我想要重写 Ext.data.TreeStore 并添加一个名为 commitChanges 的方法,在 4.1.3 版本中似乎没有这个方法),我非常确定如果将来实现了它,它将完全满足我的需求 :) - AsGoodAsItGets
2
可能有些令人惊讶,但您可以在实例上使用Ext.override,而不仅仅是类,并且在覆盖的方法中使用callParent(如函数文档中的示例所示)。 - rixo
显示剩余7条评论

3

@sra提供的答案很好,对我深入了解Ext中可用的重写功能非常有帮助,但它并未包括我最常用的实现重写的方式,大致如下:

Ext.define('my.application.form.field.Text' {
    override: 'Ext.form.field.Text'
    getValue: function () {
        // your custom functionality here
        arguments[1] = false;

        // callParent can be used if desired, or the method can be 
        // re-written without reference to the original
        this.callParent(arguments)
    }
});

我仍在使用Ext 5,因此我将在Application.js文件中加载此文件,并在其中添加到requires数组中,这将全局应用override。 我认为Ext 6项目包括一个override文件夹,只需将此文件添加到该文件夹即可确保应用override。


感谢您详细的解释和示例。 - CharanRoot

2

这是我在ExtJS 7中使用的唯一有效方法。

示例:

app/desktop/overrides/Toast.js

Ext.define(null, {
    override: 'Ext.window.Toast',
    show : function () {
        this.callParent();
// Your custom code here...
    }
});

更多关于匿名类的内容。 - A1rPun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接