我想要一个带有两个子元素的聚合物元素,一个用于生成数据,另一个用于在数据发生变化时执行某些操作(在我的情况下:向服务器发送通知)。
为了实现这一点,我写了一个聚合物元素,即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
时创建一个对象)和/或优雅的方式。那么我的问题是:在Polymer中实现这种行为的正确方法是什么?
答案 0 :(得分:1)
您是否有权修改消费者元素?
解决此问题的最佳方法是让consumer元素具有一个多属性观察器,用于侦听data属性上的子属性更改。
它可能看起来像这样:
function calc() {
console.log('hey');
};
var a = calc;
a(); // hey
这种方法的优点是,你的'consumer'元素只是'知道'当数据对象上的子属性发生变化时如何使用它。由于Polymer中数据绑定的权重较轻,尝试在'consumer'元素之外实现此行为必然会更昂贵,更复杂,因为它需要通过提供数据绑定来认为数据对象是新的它带有对副本的新引用或完全放弃数据绑定,并在事件之上构建方法并在响应事件时调用消费者的方法。所以,如果可能的话,我建议尝试上面的方法。
Polymer的数据绑定与其他一些双向启用的数据绑定实现的工作方式不同,就像您在AngularJS中可能找到的那样。 Polymer使用基于事件的“路径通知”方法,而不是使用非常昂贵的脏检查。当属性上的子属性发生更改时,具有该属性的Polymer元素将向其绑定到该属性的直接子节点触发事件,通知它们路径'property.subProperty'已更改。为了让消费者对这些变化采取行动,必须告诉他们沿着'property.subProperty'路径听取变化。我们使用上面的语法在聚合物观察者中指定路径。在这种情况下,将data。*放在我们的观察者中意味着我们希望监听数据的任何路径,以便数据属性上任何通知的属性更改都将触发观察者。
答案 1 :(得分:0)
正如您所注意到的,这并不是一种优雅的方式。你让它运作的方式很有趣。
我期望工作的另一种方法是从生产者元素中触发一个事件。
this.fire('data', {data: this.foo.bar});
然后让parent / root元素侦听此事件,然后更新使用者元素的data属性。
<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>