将自定义组件存储配置绑定到 ViewModel 存储

Posted

技术标签:

【中文标题】将自定义组件存储配置绑定到 ViewModel 存储【英文标题】:Bind custom component store config to ViewModel store 【发布时间】:2016-11-26 12:36:27 【问题描述】:

我正在用 Ext JS 编写一个自定义组件,它需要一个存储作为其配置的一部分。我想把这个 store 保存在组件的 ViewModel 中,并且我也希望它是可绑定的。目前我有这样的代码:

Ext.define('CustomComponent', 
    extend: 'Ext.container.Container',
    xtype: 'customcomponent',
    viewModel: 
        type: 'customcomponent'
    ,
    config: 
        store: 'ext-empty-store'
    ,
    initComponent: function() 
        var store = Ext.getStore(this.getConfig('store'));
        this.lookupViewModel().set('myStore', store);
        this.callParent(arguments);
    
);

Ext.define('CustomComponentViewModel', 
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.customcomponent',
    data: 
        myStore: null
    
);

由于多种原因,这并不理想:

store 配置选项不可绑定。 商店包含在 ViewModel 的 data 中,而不是 stores 中。这意味着它不能通过 ViewModel 的 getStore 方法访问。

为了使商店可绑定,我可以编写如下代码:

Ext.define('CustomComponent', 
    extend: 'Ext.container.Container',
    xtype: 'customcomponent',
    viewModel: 
        type: 'customcomponent'
    ,
    config: 
        store: 'ext-empty-store'
    ,
    publishes: 'store'
);

Ext.define('CustomComponentViewModel', 
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.customcomponent',
    data: 
        store: null
    ,
    formulas: 
        myStore: function(get) 
            return Ext.getStore(get('store'));
        
    
);

不过,这也不理想:

ViewModel 被store 配置污染,不一定是Ext.data.Store。它可以是商店的 ID 或配置对象。从本质上讲,它是一个实现细节,我希望将它保留在 ViewModel 之外,它会被每个子组件继承。 商店仍然不是 ViewModel 商店配置的一部分,因此仍然无法通过getStore 访问。

基本上,我正在寻找一种方法来设置我的 View 和 ViewModel(以及 ViewController,如果有帮助的话),这样我就可以满足这三个条件:

视图上的store 配置是可绑定的。 store 配置选项未保留在 ViewModel 中,或者以某种方式防止污染组件子级的 ViewModel。 可通过getStore 访问 ViewModel 中的商店。

是否有可能同时满足所有这三个条件?如果不是,将可绑定存储配置转换为 ViewModel 存储的最规范方法是什么? Ext JS 源码没有使用 View-ViewModel 架构来定义组件,所以我不能只看他们做了什么。

【问题讨论】:

【参考方案1】:

我相信您可以像这样使用商店。

Ext.define('CustomComponentViewModel', 
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.customcomponent',
    formulas: 
        myStore: function(get) 
            return Ext.getStore(get('store'));
        
    ,
    stores: 
        myStore: 
            fields: [
                
                    name: 'id'
                ,
                
                    name: 'name'
                ,
                
                    name: 'description'
                
            ]
        ,

);    


Ext.define('CustomComponent', 
    extend: 'Ext.container.Container',
    xtype: 'customcomponent',
    viewModel: 
        type: 'customcomponent'
    ,
    config: 
        bind: 
            store: 'myStore'
        
    
);

【讨论】:

我对你的建议有点困惑。这将如何让商店由组件设置? 我想我可能对您需要什么感到困惑。很高兴你明白了!【参考方案2】:

在更彻底地阅读了 Ext JS 6.0.2 源代码之后,我得出的结论是,如果不覆盖或继承 Ext.app.ViewModel,就不可能满足我想要的所有三个条件。我将逐一介绍标准,然后讨论我认为当前的最佳做法。

标准

store 配置必须是可绑定的

这实际上是默认完成的;所有配置选项都是可绑定的。当我说商店必须是可绑定的时,我的意思是“绑定到store 配置将更新我的 ViewModel 中的商店”。如果publishes 选项设置得当,store 配置的值将被发送到 ViewModel,即publishes: 'store'。这会将store 配置的原始值作为store 发送回ViewModel,但这不是我们想要的。我认为解决此问题的最简洁方法是通过为每个配置选项提供的apply<em>ConfigName</em> 模板方法。这是一个例子:

Ext.define('CustomComponent', 
    extend: 'Ext.container.Container',
    xtype: 'customcomponent',
    viewModel: 
        type: 'customcomponent'
    ,
    config: 
        store: 'ext-empty-store'
    ,
    publishes: 'store',
    applyStore: function(store) 
        return Ext.getStore(store);
    
);

applyStore 函数将在设置之前应用于store 的值,将其从存储 ID 或配置对象转换为实际存储。这就引出了第二个标准:

store 配置选项未保留在 ViewModel 中

通过使用applyStore 模板方法,我们可以将商店配置选项排除在我们的视图模型之外。 (实际上,它甚至将它排除在我们的视图之外!)相反,发布到我们的 ViewModel 的 store 的值是它定义的实际存储。然而不幸的是,发布配置值会将它们添加到 ViewModel 的数据对象中,而不是存储对象中。这将我们带到了最终标准:

ViewModel 中的存储可通过getStore 访问

目前无法满足此标准。原因有两个:

getStore 仅检索通过 stores 配置选项添加的商店

在 Ext JS 6.0.2 中,getStore 通过在 Ext.app.ViewModelstoreInfo 私有属性中查找存储来检索它们。 storeInfo 属性本身是通过 setupStore 私有方法设置的,该方法仅在 stores 配置的每个成员上调用。

stores 配置选项只允许配置对象

Ext.grid.Panelstore config 不同,Ext.app.ViewModelstores config 选项只允许每个store 的值是config 对象;不允许使用商店 ID 和实际商店。直接将值设置为绑定似乎可行,例如:

Ext.define('CustomComponentViewModel', 
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.customcomponent',
    data: 
        dataStore: null
    ,
    stores: 
        storeStore: 'dataStore'
    
);

但实际上,storeStore 是一个新的Ext.data.ChainedStore,它配置了source: dataStore。这意味着在storeStore 上设置过滤器和排序器不会影响dataStore,这可能不是我们想要的。

这两个限制的组合意味着不可能在 ViewModel 中设置可以使用getStore 检索的存储。

那我该怎么办?

我认为在可用选项的情况下,最好的做法是放弃使用getStore 检索商店的能力。虽然这是一个令人讨厌的不一致,但它不太可能像允许隐式 ChainedStore 那样导致细微的错误。这给了我们最终的代码:

Ext.define('CustomComponent', 
    extend: 'Ext.container.Container',
    xtype: 'customcomponent',
    viewModel: 
        type: 'customcomponent'
    ,
    config: 
        store: 'ext-empty-store'
    ,
    publishes: 'store',
    applyStore: function(store) 
        return Ext.getStore(store);
    
);

Ext.define('CustomComponentViewModel', 
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.customcomponent',
    data: 
        store: null
    
);

【讨论】:

以上是关于将自定义组件存储配置绑定到 ViewModel 存储的主要内容,如果未能解决你的问题,请参考以下文章

将自定义可序列化对象绑定到控件,以便用户和加载/保存首选项

淘汰组件(不)绑定到新内容

微信小程序将自定义组件获取的值传递给页面

微信小程序将自定义组件获取的值传递给页面

如何创建从 vue.js 实例到自定义原生 Web 组件的双向绑定?

如何将自定义复选框组件添加到 JIRA 评论?