JavaScript HTMLElement 属性上的数据绑定 在 Polymer 中

Data binding on JavaScript HTMLElement property in Polymer

本文关键字:Polymer 数据绑定 HTMLElement 属性 JavaScript      更新时间:2023-09-26

使用聚合物制作SPA,我需要我的自定义组件都使用一个通用的自定义组件,该组件代表我的后端API,并负责从/到API的GET-ting/POST-ing数据。它还充当"缓存"并保存要显示的数据。这样,有权访问此单个元素的所有组件将共享相同的数据。

所以我想做的是这个... :

<my-api
  users="{{users}}"
  products="{{products}}">
</my-api>

。但是以编程方式,因为<my-api>不是在我的所有组件中声明的,而是在顶部声明一次,然后通过JavaScript通过层次结构向下传递:

Polymer({
  is: 'my-component',
  properties: {
    api: {
      observer: '_onApiChanged',
      type: HTMLElement
    },
    products: {
       type: Array
    },
    users: {
       type: Array
    }
  },
  _onApiChanged: function(newVal, oldVal) {
    if (oldVal)
      oldVal.removeEventListener('users-changed', this._onDataChanged);
    // Listen for data changes
    newVal.addEventListener('users-changed', this._onDataChanged);
    // Forward API object to children
    this.$.child1.api = newVal;
    this.$.child2.api = newVal;
    ...
  },
  _onDataChanged: function() {
    this.users = this.api.users; // DOESN'T WORK as 'this' === <my-api>
    this.products = this.api.products; // Plus I'd have to repeat for every array
  }
});

聚合物是否提供了一种内置的方式来做到这一点?我可以通过编程方式创建双大括号绑定吗?

我可能会稍微不同地构建:利用Polymer的绑定系统以声明方式传递products/users数组。或者,您可以编写 my-api 元素,使它们都共享状态,第一个声明的元素是主元素,而将来声明的元素是副本。这将允许您在需要它们的任何位置声明它们,并通过 Polymer 的正常方式绑定到这些值。

但要回答你的问题,目前无法在不使用专用 Polymer API 的情况下以编程方式轻松设置相同类型的绑定。

为了避免重复太多,对于您遇到的绑定问题,您可以使用Polymer的内置listenunlisten方法:

Polymer({
  is: 'my-component',
  properties: {
    api: {
      observer: '_onApiChanged',
      type: HTMLElement
    },
    products: {
       type: Array
    },
    users: {
       type: Array
    }
  },
  _onApiChanged: function(newVal, oldVal) {
    var apiProperties = ['users', 'products'];
    if (oldVal) {
      apiProperties.forEach(function(prop) {
        this.unlisten(oldVal, prop + '-changed', '_onDataChanged');
      });
    }
    // Listen for data changes
    apiProperties.forEach(function(prop) {
      this.listen(newVal, prop + '-changed', '_onDataChanged');
    });
    // Forward API object to children
    this.$.child1.api = newVal;
    this.$.child2.api = newVal;
    ...
  },
  _onDataChanged: function() {
    this.users = this.api.users; // `this` should be the element now
    this.products = this.api.products;
  }
});

鉴于这是您正在执行的常见模式,您可能会从将其中一些内容提取到抽象出绑定/取消绑定和 API 元素转发的行为中获得很多好处。

您可以进行的另一个优化是查看传递给_onDataChanged的事件,看看您是否可以推断哪个值发生了变化并更新相应的属性。这可以防止您需要为每个属性添加一行。

我最终使用了另一种解决方案。任何需要访问此共享数据的元素都不会手动将顶部<my-api>元素向下传递层次结构,而是声明自己的<my-api>

然后在 <my-api> 元素的声明中,我让所有实例都使用相同的数组引用。因此,每当我更新一个时,它们都会更新,并且我不必将任何内容传递到 HTML 层次结构中,这使事情变得简单得多。