如何正确通知聚合物中兄弟姐妹之间的数据变化

How to properly notify data changes between siblings in polymer

我想要一个包含两个子元素的聚合物元素,一个生成数据,另一个在数据更改时执行某些操作(在我的例子中:向服务器发送通知)。

为了实现这一点,我编写了一个聚合物元素,即 root,具有以下结构(更改名称以简化讨论):

<producer data={{foo.bar}}></producer>
<consumer data=[[foo]]></consumer>

生产者使用 set('property', 'value') 方法更改数据,以便 root 元素看到通知。问题是 consumer 元素不会注意到对 foo 的更改,因为它们涉及子 属性.

为了解决这个问题,我尝试使用 computed binding 如下:

<producer data={{foo.bar}}></producer>
<consumer data=[[_compute(foo)]]></consumer>

...
_compute: function() {
    return this.foo;
}

然而,这不会导致 consumer 收到通知。我认为这样做的原因是返回的对象是相同的引用(只是改变了一个子属性)。目前我使用的解决方法是使用以下版本的 compute 函数:

_compute: function() {
    return Object.assign({}, this.foo);
}

这有效(consumer 元素得到通知),但我担心它可能不是最有效的(我在每次调用 _compute 时创建一个对象)and/or 优雅的方式。那么我的问题是:在 Polymer 中实现这种行为的正确方法是什么?

正如您所注意到的,没有一种优雅的方法可以做到这一点。你让它工作的方式很有趣。

我希望工作的另一种方法是从生产者元素中触发一个事件。

this.fire('data', {data: this.foo.bar});

然后让 parent/root 元素侦听此事件,然后更新消费者元素的数据 属性。

<producer on-data="handleData"></producer>
<consumer id="consumer"></consumer>

handleData: function(e) {
   self.$.consumer.data = e.detail.data;
}

编辑:

您可以创建一个新的 属性,您可以在 生产者元素中计算 。这样你就不必在每次想要访问 foo.bar

时都执行计算函数

生产者要素

properties: {
   foo: {},
   bar: {
      computed: 'computeBar(foo)'
   }
}

根元素:

<produce bar="{{bar}}"></producer>
<consumer data="[[bar]]"></consumer>

您有权修改消费者元素吗?

解决这个问题的最好方法是让消费者元素有一个 multi-property 观察者来监听 sub-property 数据变化 属性。

它可能看起来像这样:

Polymer({
    is: 'consumer',
    properties: {
        data: Object
    },
    observers: ['consumeData(data, data.*)'],
    consumeData: function (data) {
        //Do whatever you were planning on doing with data here
    }
});

这种方法的优点是您的 'consumer' 元素只是 'knows' 如何在其上的 sub-property 更改时使用数据对象。由于 Polymer 中数据绑定的轻量级方法,尝试在 'consumer' 元素之外实现此行为必然会更昂贵且更复杂,因为它需要欺骗数据绑定以认为数据对象是新的通过为其提供对副本的新引用或完全放弃数据绑定并在事件之上构建方法并调用消费者的方法以响应事件。因此,如果可能的话,我建议您尝试上述方法。

Polymer 的数据绑定与其他一些启用了 two-way 的数据绑定实现的工作方式不同,例如您可能会在 AngularJS 中找到的。 Polymer 没有使用极其昂贵的 dirty-checking,而是使用基于事件的 'path notification' 方法。当 属性 上的 sub-property 更改时,具有 属性 的 Polymer 元素将向绑定到 属性 的直接子元素触发事件,通知它们路径 'property.subProperty'变了。为了让消费者对这些变化采取行动,必须告诉它听取 'property.subProperty' 路径上的变化。我们使用上面的语法在我们的聚合物观察者中指定路径。在这种情况下,将 data.* 放在我们的观察者中意味着我们想要监听数据的任何路径,以便任何通知的 属性 数据 属性 的变化都会触发观察者。