当需要父视图模型时,Extjs使用子视图模型数据

当需要父视图模型时,Extjs使用子视图模型数据,extjs,extjs6-classic,Extjs,Extjs6 Classic,考虑这样一个代码段,它可以在右上角的组合框中运行,选择经典而不是现代: Ext.define('ReusableComponent', { xtype: 'reusable', extend: 'Ext.Container', config: { foo: 'Foo' }, updateFoo: function(foo) { this.getViewModel().set('foo', foo);

考虑这样一个代码段,它可以在右上角的组合框中运行,选择经典而不是现代:

Ext.define('ReusableComponent', {
    xtype: 'reusable',
    extend: 'Ext.Container',
    
    config: {
        foo: 'Foo'
    },
    
    updateFoo: function(foo) {
        this.getViewModel().set('foo', foo);  
    },
    
    viewModel: {
        data: {
            foo: 'Foo'
        }
    },
    
    items: [{
        bind: {
            html: 'foo = {foo}'
        }
    }]
});

Ext.define('ConcreteComponent', {
    extend: 'Ext.panel.Panel',
    
    viewModel: {
        data: {
            foo: 'Bar'
        }
    },
    
    layout: 'fit',
    items: [{
        xtype: 'reusable',
        bind: {
            foo: '{foo}'
        }
    }]
});

Ext.application({
    name : 'Fiddle',

    launch : function() {
        Ext.create('ConcreteComponent', {
            renderTo: Ext.getBody(),
            title: 'ConcreteComponent',
            width: 200,
            height: 200
        });
    }
});
我们的梦想是拥有一个可重用的组件,它将有一个定义的外部接口,并且知道它应该足够了。使用该组件的人不必知道其内部结构。在本例中,外部接口是从Ext.Container(如width/height/etc)和foo-config继承的公共配置


所以说,我试着在混凝土构件中使用它。我知道可重用组件有config foo,因此我应该能够将其绑定到我自己的viewmodel,这就是我所做的。但是这不起作用,它显示的是foo=foo,而不是预期的foo=Bar。原因似乎很清楚——我无意中使用了孩子的viewmodel中已经存在的名称,extjs选择了这个名称,而不是我在ConcreteComponent中定义的名称。例如,如何在ConcreteComponent中将viewmodel数据属性从foo重命名为foo2中解决这个问题也很清楚。但这迫使我们了解可重用组件的内部,而不仅仅是它的公共接口。有没有办法解决这个问题?或者,无论发生什么情况,子视图模型都应该始终被视为其公共界面的一部分吗?

看起来解决方案只是在私有属性下手动创建一个视图模型,该私有属性将分解组件的视图模型与其容器的视图模型之间extjs创建的视图模型的子父链,并通过viewModel配置显式地将其传递给可重用组件的子组件。使用默认值似乎效果不错。当我无意中发现颜色选择器的源代码时,我看到了解决方案。这是问题的固定代码

Ext.define('ReusableComponent', {
    xtype: 'reusable',
    extend: 'Ext.Container',
    
    config: {
        foo: 'Foo'
    },
    
    updateFoo: function(foo) {
        this.childViewModel.set('foo', foo);  
    },
    
    constructor: function() {
        this.childViewModel = Ext.create('Ext.app.ViewModel', {
            data: {
                foo: 'Foo'
            }
        });
        this.defaults = {
            viewModel: this.childViewModel
        };
        this.callParent(arguments);
    },
    
    items: [{
        bind: {
            html: 'foo = {foo}'
        }
    }]
});

Ext.define('ConcreteComponent', {
    extend: 'Ext.panel.Panel',
    
    viewModel: {
        data: {
            foo: 'Bar'
        }
    },
    
    layout: 'fit',
    items: [{
        xtype: 'reusable',
        bind: {
            foo: '{foo}'
        }
    }]
});

Ext.application({
    name : 'Fiddle',

    launch : function() {
        Ext.create('ConcreteComponent', {
            renderTo: Ext.getBody(),
            title: 'ConcreteComponent',
            width: 200,
            height: 200
        });
    }
});

使用config和updateFoo意味着您知道可重用组件中的命名,因此您可以使用不同的名称,即this.getViewModel.set'foo2',foo;使用foo作为ConcreteComponent而不用担心是的,config foo是组件的显式公共接口,任何希望使用它的人都必须知道它。内部viewmodel数据foo不可用。@LightNight在fiddle示例中,位于绑定到{foo}的可重用组件中,该组件未在其viewmodel中定义。这使得可重用组件的viewmodel成为公共接口的一部分,因为希望使用它的类必须知道在它们自己的viewmodel中提供foo,这是我想要避免的。特别是,一个严重的问题是,在同一个组件树中不能有多个ReuseAlbe组件实例,因为不能为不同的实例提供不同的foo不确定您的确切意思,您能提供所需代码的fiddle示例吗?也许有一条路可以实现你想要的。这不符合你的需要?尽管被否决,但这是直接回答原始问题的答案,也是基于官方来源