从另一个组件访问组件的数据

Get access to data of component from another component

我想从 'second-component' 获取 'first-component' 的 viewModel 并同步两个组件的 self.prop。我使用 Knockout 库。这是我的代码:

ko.components.register('first-component', {
    template: '<strong><span data-bind="text: prop"></span></strong>',
    viewModel: function(params){
        var self = this;

        self.prop = ko.observable(params.initialText);
    }
});

ko.components.register('second-component', {
template: '<div><input type="text" data-bind="value: prop">' 
          + '<button data-bind="click: foo">Click Me</button></div>',
viewModel: function(params){
        var self = this;

        self.prop = ko.observable(params.initialText);
        self.foo = function(){
        // HELP ME! I want to get viewModel of 'first-component' and 
        // synchronize self.prop for both components
            if(ko.components.isRegistered("first-component")){
            //...???

            }
        }
    }
});

在标记中使用组件:

<first-component params="initialText: 'Some text...'"></first-component>

<second-component params="initialText: 'Another text...'"></second-component>

为了方便组件和外部视图模型之间的交互,我发现最好的办法是传入一个可观察对象作为参数来管理数据的同步。我已经使用上面的代码设置了 JSFiddle example

第一个更改是创建父视图模型以包含组件之间的共享状态

var parentViewModel {
  sharedText: ko.observable('shared text')
}

然后使用共享文本作为组件的参数。对于第一个组件,initialText 设置为 sharedText,而第二个组件 sharedText 作为第二个参数传入。这是因为共享文本仅在单击 "Click Me" 按钮时更新。如果两者的 sharedText observable 都设置为 initialText,那么更新将自动发生。有时这是必需的,有时则不是。

<first-component params="initialText: sharedText"></first-component>
<second-component params="initialText: 'Initial value', sharedText: sharedText"></second-component>

然后在第一个组件中分配 属性 时,使用 params.initialText 中的引用而不是创建新的可观察对象。当knockout绑定HTML时,它会绑定到parentViewModel.sharedText,并在parentViewModel.sharedText更新时自动更新HTML。

ko.components.register('first-component', {
    template: '<strong><span data-bind="text: prop"></span></strong>', 
viewModel: function(params){
        var self = this;
        self.prop = params.initialText;
    }
});

在第二个组件中,使用初始文本创建了一个新的可观察对象,foo 单击处理程序使用来自 self.props 的值更新了 params.sharedText 引用。

ko.components.register('second-component', {
    template: '<div><input type="text" data-bind="value: prop">' 
      + '<button data-bind="click: foo">Click Me</button></div>',
    viewModel: function(params){
        var self = this;
        self.prop = ko.observable(params.initialText);
        self.foo = function(){
            params.sharedText(self.prop());
        }
    }
});

这和React组件中的状态拉升非常相似,组件传入一组属性,包括父组件的一组回调,回调负责更新共享视图模型.

我还添加了第三个组件,因为正确处理组件非常重要。有关详细信息,请参阅组件文档中的 Disposal and memory management。第三个组件是跟踪 sharedText 更新次数的计数器。它在 knockout observable 上使用订阅,如果组件从 DOM 中移除,那么它需要处理订阅。如果在组件上定义了一个dispose函数,knockout在从DOM.

中移除组件时会自动调用该方法
ko.components.register('third-component', {
    template: '<div>Counter:&nbsp;<span data-bind="text: count"></span></div>',
  viewModel: function (params) {
     var self = this;
     self.count = ko.observable(0);
     self.sub = params.sharedText.subscribe(function () {
        self.count(self.count() + 1);
     });
     self.dispose = function () {
            self.sub.dispose();
     }
  }
});